当所有 children 都有钥匙时,反应抱怨 key-less children

React complaining about key-less children when all children have keys

正如标题所说,React 在具有唯一键的列表中抛出关于 children 的错误,我不知道为什么。我正在构建一个 Twitch 聊天克隆,这发生在我的表情选择器上,其中每个可供您使用的表情都列为可点击的图标。我使用的每个地图函数都会吐出带有键的组件。我什至遍历了每个组件并添加了一个唯一的密钥,无论它是否真的需要它,但我仍然收到警告。单击前几个跟踪链接没有任何用处。

我知道我的代码可能不是很清楚,对此我深表歉意,但我们将不胜感激。

这是受影响组件的 return 声明:

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>
  );

密钥必须添加到您要返回的父包装器组件 密钥丢失 -->

{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>
                  </>

这能解决问题吗?