javascript - 当我的组件渲染时收到警告 "Warning: Each child in a list should have a unique "key"prop."

标签 javascript reactjs typescript

我正在尝试在我的 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>
  );
}

我试图通过为关键属性分配一个随机 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>
  );
}

最佳答案

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

元素键仅区分元素与其相对于其父元素的兄弟元素。这里的 div 是需要区分的兄弟元素,而不是 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中)提供稳定的标识,因此我不建议使用随机生成的键,除非您将它们存储在状态中,以便它们也很稳定(如果所有 key 都重新生成并在每次重新渲染时发生变化,则分配 key 就没有意义)。查看docs on keys了解更多信息。

关于javascript - 当我的组件渲染时收到警告 "Warning: Each child in a list should have a unique "key"prop.",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66212373/

相关文章:

javascript - 图片加载异步等待

javascript - 在 IE 中禁用滚动条

javascript - 提交表单后如何在不刷新整个页面的情况下清除之前的文本字段值?

javascript - 如何在reactjs中登录后创建 protected 路由

typescript - 如何从多个 TypeScript 文件构建单个 ES6 模块(用于前端库)

javascript - 在悬停按钮上,可见性 :visible is not working

javascript - Material-UI,如何在 typescript 中将多种样式与主题合并?

reactjs - Prettier 无法从 Visual Studio Code 中进行保存

reactjs - 如何使用 React 用三元运算符重构代码?

typescript - JSX 模式应该是 react 还是 react-native?