As the title says, React is throwing an error about children in a list having unique keys and I have no clue why. I am building a Twitch chat clone, and this is happening with my emote picker, where every emote available for your use is listed as a clickable icon. Every map function I use spits out components with keys. I even went through every single component and added a unique key whether it really needed it or not, and I am still getting the warning. Clicking the first few trace links leads to nothing useful.
I know my code might not be super clear, and I apologize for this, but any help would be appreciated.
Here is the return statement for the affected component:
return (
<Popover placement="top">
<PopoverTrigger>
<Button disabled={!loggedIn || !connected}>
{
<Box
as="img"
width={[12, 10, 10, 8]}
alt="Emote Picker"
// src="https://static-cdn.jtvnw.net/emoticons/v2/305954156/static/light/3.0" // PogChamp
src="https://static-cdn.jtvnw.net/emoticons/v2/307445021/static/light/3.0" // Orangie
title="Emote Picker"
/>
}
</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<Flex height={400} overflow="auto" direction="column">
{showBTTVChannel && (
<>
<PopoverHeader>BTTV Channel Emotes</PopoverHeader>
<PopoverBody>
<Flex flexWrap="wrap">
{bttvEmotes !== null &&
// eslint-disable-next-line array-callback-return
Object.keys(bttvEmotes).map((key, index) => {
if (bttvEmotes[key]['category'] === 'bttv_channel') {
return (
<ChatEmote
key={index}
name={key}
src={
bttvEmotes[key][userOptions.emoteQuality 'x']
}
height={8}
margin={1.5}
onClick={() => onClickHandler(key)}
/>
);
}
})}
</Flex>
</PopoverBody>
</>
)}
{showFFZChannel && (
<>
<PopoverHeader>FFZ Channel Emotes</PopoverHeader>
<PopoverBody>
<Flex flexWrap="wrap">
{bttvEmotes !== null &&
// eslint-disable-next-line array-callback-return
Object.keys(bttvEmotes).map((key, index) => {
if (bttvEmotes[key]['category'] === 'ffz_channel') {
return (
<ChatEmote
key={index}
name={key}
src={
bttvEmotes[key][userOptions.emoteQuality 'x']
}
height={8}
margin={1.5}
onClick={() => onClickHandler(key)}
/>
);
}
})}
</Flex>
</PopoverBody>
</>
)}
{showBTTVShared && (
<>
<PopoverHeader>BTTV Shared Emotes</PopoverHeader>
<PopoverBody>
<Flex flexWrap="wrap">
{bttvEmotes !== null &&
// eslint-disable-next-line array-callback-return
Object.keys(bttvEmotes).map((key, index) => {
if (bttvEmotes[key]['category'] === 'bttv_shared') {
return (
<ChatEmote
key={index}
name={key}
src={
bttvEmotes[key][userOptions.emoteQuality 'x']
}
height={8}
margin={1.5}
onClick={() => onClickHandler(key)}
/>
);
}
})}
</Flex>
</PopoverBody>
</>
)}
{showEmotes &&
// eslint-disable-next-line array-callback-return
Object.keys(emoteSets.current).map(key => {
if (key !== 'Twitch Global') {
return (
<>
<PopoverHeader>{key}</PopoverHeader>
<PopoverBody>
<Flex flexWrap="wrap">
{emoteSets.current !== null &&
Object.keys(emoteSets.current[key]['emotes']).map(
(key, index) => {
return (
<ChatEmote
key={index}
name={key}
src={
userEmotes[key][
userOptions.emoteQuality 'x'
]
}
height={8}
margin={1.5}
onClick={() => onClickHandler(key)}
/>
);
}
)}
</Flex>
</PopoverBody>
</>
);
}
})}
<PopoverHeader>BTTV Global Emotes</PopoverHeader>
<PopoverBody>
<Flex flexWrap="wrap">
{bttvEmotes !== null &&
// eslint-disable-next-line array-callback-return
Object.keys(bttvEmotes).map((key, index) => {
if (bttvEmotes[key]['category'] === 'bttv_global') {
return (
<ChatEmote
key={index}
name={key}
src={bttvEmotes[key][userOptions.emoteQuality 'x']}
height={8}
margin={1.5}
onClick={() => onClickHandler(key)}
/>
);
}
})}
</Flex>
</PopoverBody>
{showEmotes && (
<>
<PopoverHeader>Twitch Global</PopoverHeader>
<PopoverBody>
<Flex flexWrap="wrap">
{emoteSets.current !== null &&
Object.keys(
emoteSets.current['Twitch Global']['emotes']
).map((key, index) => {
return (
<ChatEmote
key={index}
name={key}
src={userEmotes[key][userOptions.emoteQuality 'x']}
height={8}
margin={1.5}
onClick={() => onClickHandler(key)}
/>
);
})}
</Flex>
</PopoverBody>
</>
)}
</Flex>
</PopoverContent>
</Popover>
);
CodePudding user response:
key must added to the parent wrapper component which you're returning key is missing -->
{showEmotes &&
// eslint-disable-next-line array-callback-return
//map second argument return the index of current element
Object.keys(emoteSets.current).map((key,i) => {
if (key !== 'Twitch Global') {
return (
//missing key
<div key={i}>
<PopoverHeader>{key}</PopoverHeader>
<PopoverBody>
<Flex flexWrap="wrap">
{emoteSets.current !== null &&
Object.keys(emoteSets.current[key]['emotes']).map(
(key, index) => {
return (
<ChatEmote
key={index}
name={key}
src={
userEmotes[key][
userOptions.emoteQuality 'x'
]
}
height={8}
margin={1.5}
onClick={() => onClickHandler(key)}
/>
);
}
)}
</Flex>
</PopoverBody>
</>
does this solve issue ?