【问题标题】:Getting warning "Warning: Each child in a list should have a unique "key" prop." when my component render收到警告“警告:列表中的每个孩子都应该有一个唯一的“关键”道具。”当我的组件渲染时
【发布时间】:2021-02-16 01:18:42
【问题描述】:

我正在尝试在我的 react 应用程序中消除此警告:

Warning: Each child in a list should have a unique "key" prop.

Check the render method of `SettingRadioButtonGroup`. See https://reactjs.org/link/warning-keys for more information.
    at div
    at SettingRadioButtonGroup (http://localhost:3000/main_window/index.js:92979:171)
    at div
    at CardBody (http://localhost:3000/main_window/index.js:56308:27)
    at div
    at Transition (http://localhost:3000/main_window/index.js:85807:30)
    at http://localhost:3000/main_window/index.js:50905:22
    at AccordionCollapse (http://localhost:3000/main_window/index.js:49335:23)
    at div
    at Card (http://localhost:3000/main_window/index.js:49995:23)
    at div
    at SettingGroup (http://localhost:3000/main_window/index.js:92935:15)
    at TestSettingGroup (http://localhost:3000/main_window/index.js:93093:22)
    at div
    at Accordion (http://localhost:3000/main_window/index.js:49282:96)
    at div
    at ModalBody (http://localhost:3000/main_window/index.js:56308:27)
    at div
    at div
    at ModalDialog (http://localhost:3000/main_window/index.js:53383:23)
    at div
    at Transition (http://localhost:3000/main_window/index.js:85807:30)
    at Fade (http://localhost:3000/main_window/index.js:51637:24)
    at DialogTransition
    at Modal (http://localhost:3000/main_window/index.js:84195:24)
    at Modal (http://localhost:3000/main_window/index.js:53061:23)
    at App (http://localhost:3000/main_window/index.js:92660:22)

这是我的SettingRadioButtonGroup组件的代码:

import { nanoid } from "nanoid";
import React, { useState } from "react";
import { Form, InputGroup } from "react-bootstrap";

export type RadioButtonGroup = {
  desc: string;
  isSelected: boolean;
};

export interface SettingRadioButtonGroupProps
{
  groupDesc: string;
  radioButtons: RadioButtonGroup[];
  onRadioSelected: (selectedItem: string) => void;
};

export function SettingRadioButtonGroup(props: SettingRadioButtonGroupProps)
{
  const radioGroupName = nanoid();
  return (
    <div className="radio-group">
      <p className="radio-label">{props.groupDesc}</p>
      <div className="group">
        {
          props.radioButtons.map((button) =>
          {
            if (button.isSelected)
              props.onRadioSelected(button.desc);

            const buttonLabel = nanoid();
            return (
              <div className="radio-button">
                <input type="radio" id={buttonLabel} name={radioGroupName} onClick={() => { () => props.onRadioSelected(button.desc) }} />
                <label htmlFor={radioGroupName}>{button.desc}</label>
              </div>
            );
          })
        }
      </div>
    </div>
  );
}

这是生成这些组件的组件:

import { useState } from "react";
import { TextBoxSetting } from "./Components/TextBoxSetting";
import { SettingGroup } from "./Components/SettingGroup";
import SettingGroupBaseProps from "./Components/SettingGroupBaseProps";
import { RadioButtonGroup, SettingRadioButtonGroup } from "./Components/SettingRadioButtonGroup";
import faker from  "faker/locale/fr_CA";

export default function TestSettingGroup(props: SettingGroupBaseProps)
{
  const [textInput, setTextInput] = useState<string>();

  const radioButton: RadioButtonGroup[] = [];
  for (let i = 0; i <= 8; i++) {
    radioButton.push({
      desc: faker.lorem.word(),
      isSelected: false
    })
  }

  const [buttonSelected, setButtonSelected] = useState<string>();
  import("lodash")
    .then((_) =>
    {
      const selected = _.find(radioButton, (value) => value.isSelected);
      if (selected)
        setButtonSelected(selected.desc);
    })
    .catch();



  function onSave()
  {

    const settings = {
      textBoxSetting: textInput,
      radioButtonSelected: buttonSelected
    };

    console.table(settings);
  }


  return (
    <SettingGroup name={props.name} desc={props.desc} onSave={onSave}>
      <TextBoxSetting onTextEntered={(e) => setTextInput(e)} name="Text box setting component" />
      <SettingRadioButtonGroup groupDesc={"Radio button group"} radioButtons={radioButton} onRadioSelected={setButtonSelected} />
    </SettingGroup>
  );
}

我试图通过为 key 属性分配一个随机 id 来消除警告,如下所示,但是我仍然有警告,它导致组件创建一个错误,当我单击单选按钮时它会生成一个新的单选按钮.它还会产生以下警告:

Warning: Encountered two children with the same key, `tvehx36gLi-hG56z68RTg`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
    at div
    at div
    at div
    at SettingRadioButtonGroup (http://localhost:3000/main_window/index.js:92980:171)
    at div
    at CardBody (http://localhost:3000/main_window/index.js:56308:27)
    at div
    at Transition (http://localhost:3000/main_window/index.js:85807:30)
    at http://localhost:3000/main_window/index.js:50905:22
    at AccordionCollapse (http://localhost:3000/main_window/index.js:49335:23)
    at div
    at Card (http://localhost:3000/main_window/index.js:49995:23)
    at div
    at SettingGroup (http://localhost:3000/main_window/index.js:92935:15)
    at TestSettingGroup (http://localhost:3000/main_window/index.js:93094:22)
    at div
    at Accordion (http://localhost:3000/main_window/index.js:49282:96)
    at div
    at ModalBody (http://localhost:3000/main_window/index.js:56308:27)
    at div
    at div
    at ModalDialog (http://localhost:3000/main_window/index.js:53383:23)
    at div
    at Transition (http://localhost:3000/main_window/index.js:85807:30)
    at Fade (http://localhost:3000/main_window/index.js:51637:24)
    at DialogTransition
    at Modal (http://localhost:3000/main_window/index.js:84195:24)
    at Modal (http://localhost:3000/main_window/index.js:53061:23)
    at App (http://localhost:3000/main_window/index.js:92660:22)
overrideMethod @ react_devtools_backend.js:2430
printWarning @ react-dom.development.js:67
error @ react-dom.development.js:43
warnOnInvalidKey @ react-dom.development.js:13620
reconcileChildrenArray @ react-dom.development.js:13651
reconcileChildFibers @ react-dom.development.js:14125
reconcileChildren @ react-dom.development.js:16990
updateHostComponent @ react-dom.development.js:17632
beginWork @ react-dom.development.js:19080
beginWork$1 @ react-dom.development.js:23940
performUnitOfWork @ react-dom.development.js:22776
workLoopSync @ react-dom.development.js:22707
renderRootSync @ react-dom.development.js:22670
performSyncWorkOnRoot @ react-dom.development.js:22293
(anonymous) @ react-dom.development.js:11327
unstable_runWithPriority @ scheduler.development.js:646
runWithPriority$1 @ react-dom.development.js:11276
flushSyncCallbackQueueImpl @ react-dom.development.js:11322
flushSyncCallbackQueue @ react-dom.development.js:11309
discreteUpdates$1 @ react-dom.development.js:22420
discreteUpdates @ react-dom.development.js:3756
dispatchDiscreteEvent @ react-dom.development.js:5889
9react_devtools_backend.js:2430 Warning: Encountered two children with the same key, `wFq9eikLw6B_LN98bUqCV`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
    at div
    at div
    at div
    at SettingRadioButtonGroup (http://localhost:3000/main_window/index.js:92980:171)
    at div
    at CardBody (http://localhost:3000/main_window/index.js:56308:27)
    at div
    at Transition (http://localhost:3000/main_window/index.js:85807:30)
    at http://localhost:3000/main_window/index.js:50905:22
    at AccordionCollapse (http://localhost:3000/main_window/index.js:49335:23)
    at div
    at Card (http://localhost:3000/main_window/index.js:49995:23)
    at div
    at SettingGroup (http://localhost:3000/main_window/index.js:92935:15)
    at TestSettingGroup (http://localhost:3000/main_window/index.js:93094:22)
    at div
    at Accordion (http://localhost:3000/main_window/index.js:49282:96)
    at div
    at ModalBody (http://localhost:3000/main_window/index.js:56308:27)
    at div
    at div
    at ModalDialog (http://localhost:3000/main_window/index.js:53383:23)
    at div
    at Transition (http://localhost:3000/main_window/index.js:85807:30)
    at Fade (http://localhost:3000/main_window/index.js:51637:24)
    at DialogTransition
    at Modal (http://localhost:3000/main_window/index.js:84195:24)
    at Modal (http://localhost:3000/main_window/index.js:53061:23)
    at App (http://localhost:3000/main_window/index.js:92660:22)
import { nanoid } from "nanoid";
import React, { useState } from "react";
import { Form, InputGroup } from "react-bootstrap";
import { RadioButtonGroup } from "./SettingRadioButtonGroup";


export interface SettingCheckboxButtonGroupProps
{
  groupDesc: string;
  checkboxButtons: RadioButtonGroup[];
  onCheckboxSelected: (selectedItem: string) => void;
};

export function SettingChecboxButtonGroup(props: SettingCheckboxButtonGroupProps)
{
  const radioGroupName = nanoid();
  return (
    <div className="radio-group">
      <p className="radio-label">{props.groupDesc}</p>
      <div className="group">
        {
          props.checkboxButtons.map((button) =>
          {
            if (button.isSelected)
              props.onCheckboxSelected(button.desc);

            const buttonLabel = nanoid();
            return (
              <div className="radio-button">
                <input key={radioGroupName} type="checkbox" id={buttonLabel} name={radioGroupName} onClick={() => { () => props.onCheckboxSelected(button.desc); }} />
                <label key={radioGroupName} htmlFor={radioGroupName}>{button.desc}</label>
              </div>
            );
          })
        }
      </div>
    </div>
  );
}

【问题讨论】:

  • 你需要&lt;div className="radio-button" key={button.desc}&gt;
  • 键应该在映射的返回值(div)上。如果您正在生成重复的随机密钥,那么该逻辑可能存在问题。

标签: javascript reactjs typescript


【解决方案1】:

您需要将键放在map 中最外层的元素上。

元素键仅将元素与其相对于其父元素的兄弟元素区分开来。这里divs 是需要区分的兄弟元素,而不是inputlabel 元素。

例子:

<div key={radioGroupName} className="radio-button">
    <input type="checkbox" id={buttonLabel} name={radioGroupName} onClick={() => { () => props.onCheckboxSelected(button.desc); }} />
    <label htmlFor={radioGroupName}>{button.desc}</label>
</div>

此外,密钥用于为动态生成的元素(在循环中/map)提供稳定的身份,因此我不建议使用随机生成的密钥,除非您将它们存储在状态中以便它们也稳定(如果所有键都重新生成并在每次重新渲染时更改,则分配键没有意义)。查看docs on keys 了解更多信息。

【讨论】:

  • 这是关键答案。反应文档并没有说它必须在最外层的元素中,我认为我是一步一步地跟随的。
【解决方案2】:

在 React 中,每次你要从数组中渲染一系列项目时,例如使用 map 函数,你必须为每个项目提供一个 唯一键 以帮助 React引擎识别每一个,在您的示例中,您可以执行以下操作来修复:

props.radioButtons.map((button, index) =>
  {
    if (button.isSelected)
      props.onRadioSelected(button.desc);

    const buttonLabel = nanoid();
    return (
      <div key={buttonLabel} className="radio-button">
        <input type="radio" id={buttonLabel} name={radioGroupName} onClick={() => { () => props.onRadioSelected(button.desc) }} />
        <label htmlFor={radioGroupName}>{button.desc}</label>
      </div>
    );
  })
}

&lt;div key={buttonLabel} className="radio-button"&gt;查看更改

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-26
    • 2021-06-17
    • 2019-08-04
    • 2021-01-12
    • 2022-06-28
    • 2023-02-17
    • 2019-12-05
    • 2021-09-05
    相关资源
    最近更新 更多