了解 React.js 中数组子项的唯一键

Understanding unique keys for array children in React.js

提问人:Brett DeWoody 提问时间:2/5/2015 最后编辑:Brett DeWoody 更新时间:11/7/2023 访问量:1280598

问:

我正在构建一个接受 JSON 数据源并创建可排序表的 React 组件。
每个动态数据行都有一个分配给它的唯一键,但我仍然收到以下错误:

数组中的每个子项都应该有一个唯一的“key”属性。
检查 TableComponent 的 render 方法。

我的渲染方法返回:TableComponent

<table>
  <thead key="thead">
    <TableHeader columns={columnNames}/>
  </thead>
  <tbody key="tbody">
    { rows }
  </tbody>
</table>

该组件是单行,并且还为其分配了一个唯一键。TableHeader

每个 in 都是由具有唯一键的组件构建的:rowrows

<TableRowItem key={item.id} data={item} columns={columnNames}/>

看起来像这样:TableRowItem

var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c) {
          return <td key={this.props.data[c]}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

是什么导致了唯一键属性错误?

JavaScript 反应JS

评论

14赞 Kiril 2/5/2015
JS 数组中的行应该具有唯一属性。它将帮助 ReactJS 找到对相应 DOM 节点的引用,并仅更新标记内的内容,但不重新渲染整个表/行。key
1赞 nilgun 2/5/2015
你也可以共享数组,或者更确切地说是 jsfiddle 吗?顺便说一句,您不需要房产。rowskeytheadtbody
0赞 Brett DeWoody 2/5/2015
我在原始问题@nilgun中添加了行组件。
3赞 nilgun 2/5/2015
是否有可能某些项目没有 ID 或具有相同的 ID?

答:

928赞 jmingov 2/5/2015 #1

您应该为每个子项以及子项中的每个元素添加一个键。

这样 React 就可以处理最小的 DOM 更改。

在您的代码中,每个都试图在没有密钥的情况下呈现其中的一些子项。<TableRowItem key={item.id} data={item} columns={columnNames}/>

请看这个例子

尝试从 div 内的元素中删除 (并检查控制台)。key={i}<b></b>

在示例中,如果我们没有给元素一个键,我们只想更新 ,React 需要重新渲染整行而不是只渲染元素。<b>object.city

代码如下:

const data = [
  { name: "Nuri", age: 28, city: "HO" },
  { name: "Talib", age: 82, city: "HN" },
  { name: "Jenny", age: 41, city: "IT" },
];

const ExampleComponent = React.createClass({
  render: function () {
    const infoData = this.props.info;
    return (
      <div>
        {infoData.map((object, i) => {
          return (
            <div className={"row"} key={i}>
              {[
                object.name,
                // remove the key
                <b className="fosfo" key={i}>
                  {" "}
                  {object.city}{" "}
                </b>,
                object.age,
              ]}
            </div>
          );
        })}
      </div>
    );
  },
});

React.render(<ExampleComponent info={data} />, document.body);

底部@Chris发布的答案比这个答案要详细得多。

关于密钥在对账中的重要性的 React 文档:密钥

评论

6赞 Deke 2/27/2016
我遇到了完全相同的错误。聊天后这个问题解决了吗?如果是这样,您能否发布此问题的更新。
474赞 Davor Lucic 8/9/2016
为什么 React 自己很难生成唯一的键?
15赞 koddo 10/6/2016
@DavorLucic,这里有一个讨论:github.com/facebook/react/issues/1342#issuecomment-39230939
6赞 sameers 1/12/2017
这几乎是上面链接的问题聊天中所说的官方说法:键是关于集合成员的身份,为从任意迭代器中出现的项目自动生成键可能会在 React 库中影响性能。
7赞 Michael Martin-Smucker 5/26/2018
是否有文档解释为什么不仅子节点需要唯一键,而且这些子节点的节点也需要唯一键?我在文档中找不到任何关于这方面的内容。
887赞 Chris 5/10/2017 #2

迭代数组时要小心!!

一个常见的误解是,使用数组中元素的索引是抑制您可能熟悉的错误的可接受方法:

Each child in an array should have a unique "key" prop.

然而,在许多情况下,事实并非如此!这是反模式在某些情况下可能导致不需要的行为


了解道具key

React 使用 prop 来理解组件到 DOM 元素的关系,然后将其用于协调过程。因此,键始终保持唯一性非常重要,否则 React 很有可能会混淆元素并改变不正确的元素。同样重要的是,这些关键帧在所有重新渲染过程中保持静态,以保持最佳性能。key

话虽如此,只要知道数组是完全静态的,并不总是需要应用上述内容。但是,鼓励尽可能应用最佳实践。

一位 React 开发者在 GitHub 上说

  • 关键不是真正的性能,而是更多的身份(这反过来又会带来更好的性能)。随机分配和更改的值不是标识
  • 在不知道您的数据是如何建模的情况下,我们无法[自动]提供密钥。如果您没有 id,我建议也许使用某种哈希函数
  • 当我们使用数组时,我们已经有了内部键,但它们是数组中的索引。插入新元素时,这些键是错误的。

简而言之,a 应该是:key

  • 唯一 - 键不能与同级组件的键相同。
  • 静态 - 在渲染之间不应更改关键帧。

使用道具key

根据上面的说明,请仔细研究以下示例,并在可能的情况下尝试实施推荐的方法。


坏(可能)

<tbody>
    {rows.map((row, i) => {
        return <ObjectRow key={i} />;
    })}
</tbody>

这可以说是在 React 中迭代数组时最常见的错误。这种方法在技术上并不是“错误的”,只是......如果你不知道自己在做什么,那就“危险”了。如果你正在迭代一个静态数组,那么这是一个完全有效的方法(例如,导航菜单中的链接数组)。但是,如果您要添加、删除、重新排序或过滤项目,则需要小心。请看官方文档中的详细解释

class MyApp extends React.Component {
  constructor() {
    super();
    this.state = {
      arr: ["Item 1"]
    }
  }
  
  click = () => {
    this.setState({
      arr: ['Item ' + (this.state.arr.length+1)].concat(this.state.arr),
    });
  }
  
  render() {
    return(
      <div>
        <button onClick={this.click}>Add</button>
        <ul>
          {this.state.arr.map(
            (item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item>
          )}
        </ul>
      </div>
    );
  }
}

const Item = (props) => {
  return (
    <li>
      <label>{props.children}</label>
      <input value={props.text} />
    </li>
  );
}

ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

在这个代码片段中,我们使用的是一个非静态数组,我们并不局限于将其用作堆栈。这是一种不安全的方法(你会明白为什么)。请注意,当我们将项目添加到数组的开头(基本上是不移位)时,每个项目的值都保持不变。为什么?因为 并不能唯一标识每个项目。<input>key

换句话说,起初有.当我们添加第二项时,顶部项目变为 ,后跟作为第二项。但是,现在有,不再有。取而代之的是,现在有!!Item 1key={0}Item 2Item 1Item 1key={1}key={0}Item 2key={0}

因此,React 认为元素没有改变,因为 with 键总是在顶部!<input>Item0

那么,为什么这种方法有时很糟糕呢?

仅当以某种方式筛选、重新排列数组或添加/删除项目时,此方法才有风险。如果它始终是静态的,那么使用起来是完全安全的。例如,可以使用此方法安全地迭代导航菜单,因为您可能永远不会添加新链接或重新排列它们。["Home", "Products", "Contact us"]

简而言之,这是您可以安全地使用索引的时候:key

  • 数组是静态的,永远不会改变。
  • 从不筛选数组(显示数组的子集)。
  • 数组永远不会重新排序。
  • 该阵列用作堆栈或后进先出(后进先出)。换句话说,添加只能在数组的末尾完成(即 push),并且只能删除最后一项(即 pop)。

如果我们在上面的代码片段中将添加的项目推送到数组的末尾,则每个现有项目的顺序将始终是正确的。


很差

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={Math.random()} />;
    })}
</tbody>

虽然这种方法可能会保证键的唯一性,但它总是会强制 react 重新呈现列表中的每个项目,即使这不是必需的。这是一个非常糟糕的解决方案,因为它极大地影响了性能。更不用说,在两次产生相同数字的情况下,不能排除密钥冲突的可能性。Math.random()

不稳定的键(如由 生成的键)将导致许多组件实例和 DOM 节点被不必要地重新创建,这可能会导致性能下降和子组件状态丢失。Math.random()


非常好

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={row.uniqueId} />;
    })}
</tbody>

这可以说是最好的方法,因为它使用对数据集中每个项目唯一的属性。例如,如果包含从数据库获取的数据,则可以使用表的主键(通常是一个自动递增的数字)。rows

选取键的最佳方法是使用一个字符串,该字符串在其同级中唯一标识列表项。大多数情况下,您会使用数据中的 ID 作为键


componentWillMount() {
  let rows = this.props.rows.map(item => { 
    return {uid: SomeLibrary.generateUniqueID(), value: item};
  });
}

...

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={row.uid} />;
    })}
</tbody>

这也是一个好方法。如果您的数据集不包含任何保证唯一性的数据(例如任意数字数组),则存在键冲突的可能性。在这种情况下,最好在循环访问数据集中的每个项目之前手动为其生成唯一标识符。最好在挂载组件或接收数据集时(例如,从 props 或异步 API 调用),以便只执行此操作一次,而不是每次组件重新渲染时。已经有一些库可以为您提供这样的密钥。下面是一个示例:react-key-index

评论

3赞 skube 8/3/2017
官方文档中,它们用于转换为字符串而不是保留为数字。记住这一点重要吗?toString()
3赞 Chris 8/3/2017
@skube,不,您也可以使用整数。不知道他们为什么要转换它。key
3赞 Chris 8/4/2017
@skube,是的,这是完全可以接受的。如上面的示例所述,您可以使用迭代数组的项索引(这是一个整数)。甚至文档也指出:“作为最后的手段,您可以将数组中项目的索引作为键传递”。但是,无论如何,总是以字符串结束。key
2赞 farmcommand2 3/9/2018
此键应该仅在该数组中是唯一的,还是在整个应用程序中是唯一的?
4赞 Chris 3/9/2018
@farmcommand2,键应用于 React 组件,并且需要在兄弟姐妹中是唯一的。如上所述。换句话说,在数组中是唯一的
5赞 Shashank Malviya 4/28/2018 #3

警告:数组或迭代器中的每个子项都应该有一个唯一的“key”属性。

这是一个警告,因为对于我们将要迭代的数组项,需要具有独特的相似性。

React 将迭代组件渲染处理为数组。

解决此问题的更好方法是为要迭代的数组项提供索引。例如:

class UsersState extends Component
    {
        state = {
            users: [
                {name:"shashank", age:20},
                {name:"vardan", age:30},
                {name:"somya", age:40}
            ]
        }
    render()
        {
            return(
                    <div>
                        {
                            this.state.users.map((user, index)=>{
                                return <UserState key={index} age={user.age}>{user.name}</UserState>
                            })
                        }
                    </div>
                )
        }

index 是 React 内置的 props。

评论

2赞 Chris 4/28/2018
如果以某种方式重新排列项目,则此方法具有潜在危险。但是,如果它们保持静止,那么这很好。
0赞 Shashank Malviya 6/7/2018
@chris我完全同意你的看法,因为在这种情况下,索引可能是重复的。最好对键使用动态值。
0赞 Shashank Malviya 7/11/2018
@chris我也同意你的评论。我们应该使用动态值而不是索引,因为可能存在重复项。为了简单起见,我这样做了。顺便说一句,感谢您的贡献(已投赞成票)
7赞 Mahdi Bashirpour 5/27/2018 #4

只需将唯一键添加到您的组件中

data.map((marker)=>{
    return(
        <YourComponents 
            key={data.id}     // <----- unique key
        />
    );
})

评论

0赞 PeakCode 3/24/2023
密钥在 .data.idYourComponents
1赞 prime 9/24/2018 #5

这是一个警告,但解决这个问题将使 Reacts 渲染速度更快

这是因为需要唯一标识列表中的每个项目。比方说,如果该列表的某个元素在 Reacts 中的状态发生了变化,那么 React 需要弄清楚哪个元素发生了变化,以及它在 DOM 中的位置需要改变,以便浏览器 DOM 与 Reacts 虚拟 DOM 同步。ReactVirtual DOM

作为解决方案,只需为每个标签引入一个属性即可。这应该是每个元素的唯一值。keylikey

评论

0赞 Chris 9/26/2018
这并不完全正确。如果添加道具,渲染速度不会更快。如果你没有提供,React 会自动分配一个(迭代的当前索引)。key
0赞 prime 9/26/2018
@Chris在这种情况下,为什么要发出警告?
0赞 Chris 9/26/2018
因为如果不提供密钥,React 就不知道你的数据是如何建模的。如果修改了数组,这可能会导致意外结果。
0赞 prime 9/26/2018
@Chris在数组修改的情况下,如果我们没有提供键,React 会根据它更正索引吗?无论如何,我认为从 React 中删除额外的开销会对渲染过程产生一些影响。
0赞 Chris 9/26/2018
同样,React 基本上可以。因此,这取决于数组包含的数据。例如,如果您有 列表 ,那么显然沃尔沃是由键和特斯拉标识的 - 因为这是它们在循环中出现的顺序。现在,如果对数组重新排序,则键将被交换。对于 React 来说,由于 “object” 仍然位于顶部,因此它更愿意将此更改解释为“重命名”,而不是重新排序。这里的正确键需要按顺序排列,然后 .您并不总是在运行时中期重新排序,但当您这样做时,这是一种风险。key={i}["Volvo", "Tesla"]01010
15赞 Gerd 4/12/2019 #6

检查:key = undef !!

您还收到了警告消息:

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

如果你的代码是完整的,但如果你的代码是正确的,但如果打开。

<ObjectRow key={someValue} />

someValue 未定义!!请先检查一下。您可以节省时间。

评论

0赞 ofri cofri 7/12/2022
从字面上看,得救了!
1赞 Ramesh 11/25/2019 #7
var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c, i) {
          return <td key={i}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

这将引发问题。

3赞 Khadim H. 1/17/2020 #8

在 react 中定义唯一键的最佳解决方案: 在映射中,您初始化了名称 post,然后由 key={post.id} 定义键,或者在我的代码中,您看到我定义了名称项,然后我通过 key={item.id} 定义键:

<div className="container">
                {posts.map(item =>(

                    <div className="card border-primary mb-3" key={item.id}>
                        <div className="card-header">{item.name}</div>
                    <div className="card-body" >
                <h4 className="card-title">{item.username}</h4>
                <p className="card-text">{item.email}</p>
                    </div>
                  </div>
                ))}
            </div>

评论

0赞 Uday 10/1/2023
正在寻找同样的答案,即使我有这样的组件并且感到沮丧
65赞 apil.tamang 2/12/2020 #9

这可能对某人有帮助,也可能没有帮助,但它可能是一个快速参考。这也与上面介绍的所有答案相似。

我有很多位置使用以下结构生成列表:

return (
    {myList.map(item => (
       <>
          <div class="some class"> 
             {item.someProperty} 
              ....
          </div>
       </>
     )}
 )
         

经过一些反复试验(以及一些挫折),在最外层的块中添加一个关键属性解决了它。另外,请注意,标签现在已替换为现在的标签。<><div>

return (
  
    {myList.map((item, index) => (
       <div key={index}>
          <div class="some class"> 
             {item.someProperty} 
              ....
          </div>
       </div>
     )}
 )

当然,在上面的例子中,我一直天真地使用迭代索引(index)来填充键值。理想情况下,应使用列表项独有的内容。

评论

5赞 Amon 3/29/2020
这非常有帮助,谢谢!我什至没有意识到我必须把它放在最外层
0赞 orangeberri07 7/1/2020
我正在做类似的分组,但有表格行。不能将表格行换行包装在 div 中。取而代之的是,用键将其包装在 react Fragment 中,如下所示: stackoverflow.com/a/51875412/750914
17赞 Vuong Dang 12/8/2020
<> 是 <React.Fragment> 的简短语法。因此,如果你想添加一个键,你可以这样做:<React.Fragment key={item.id}>
1赞 miriyo 1/25/2021
我在使用 Material-UI 时遇到了同样的问题,我使用列表(以及其他地方的菜单)并将这些组件的子项放在工具提示中。为工具提示提供“键”而不是 ListItem/MenuItem 本身可以消除警告。
1赞 enko 10/31/2022
谢谢,删除空标签(为方便起见而添加)解决了它。
2赞 Felipe 3/24/2020 #10

我遇到了此错误消息,因为在需要返回时返回了数组中的某些项目。<></>null

4赞 Supun Praneeth 10/27/2020 #11

在 ReactJS 中,如果你要渲染一个元素数组,你应该为每个元素都有一个唯一的键。通常,这些情况正在创建一个列表。

例:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

在上面的示例中,它使用 tag 创建一个动态列表,因此由于 tag 没有唯一键,因此它显示错误。lili

修复后:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li key={n}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

当您没有唯一键时使用 map 时的替代解决方案(react eslint 不建议这样做):

function List() {
  const numbers = [0,1,2,3,4,4];
 
  return (
    <ul>{numbers.map((n,i) => <li key={i}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

现场示例:https://codepen.io/spmsupun/pen/wvWdGwG

2赞 Arvind 12/15/2020 #12

我有一个唯一的密钥,只需要像这样将它作为道具传递:

<CompName key={msg._id} message={msg} />

此页面很有帮助:

https://reactjs.org/docs/lists-and-keys.html#keys

5赞 Nasreen Ustad 2/12/2021 #13

当您没有呈现项的稳定 ID 时,您可以将项索引用作键作为最后的手段:

const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
   <li key={index}>
      {todo.text}
   </li>
);

请参考 List 和 Keys - React

2赞 superup 4/15/2021 #14

就我而言,将 id 设置为标记

<tbody key={i}>

问题解决了。

1赞 Vik2696 4/16/2021 #15
If you are getting error like :

> index.js:1 Warning: Each child in a list should have a unique "key" prop.

Check the render method of `Home`. See https://reactjs.org/link/warning-keys for more information.

Then Use inside map function like:

  {classes.map((user, index) => (
              <Card  **key={user.id}**></Card>
  ))}`enter code here`
8赞 Foyez 6/15/2021 #16

您应该对其中的每个子键使用唯一值tbody

  • 该值不能与其同级值不相同(相同)
  • 不应在渲染之间更改

例如,键值可以是数据库 IDUUID(通用唯一标识符)。

这里的键是手动处理的:

<tbody>
  {rows.map((row) => <ObjectRow key={row.uuid} />)}
</tbody>

你也可以让 React 使用 React.Children.toArray 处理键

<tbody>
  {React.Children.toArray(rows.map((row) => <ObjectRow />))}
</tbody>
-3赞 A K M Intisar Islam 7/26/2021 #17

我遇到了类似的问题,但不完全是。尝试了所有可能的解决方案,但无法摆脱该错误

数组中的每个子项都应该有一个唯一的“key”属性。

然后我尝试在另一个本地主机中打开它。我不知道怎么做,但它奏效了!

评论

0赞 Mohamed Raza 8/12/2021
table 标签内的 ' rowKey={(item) => item.id}' 属性解决了我的问题
2赞 Gangula 11/3/2021
这很可能是浏览器缓存的问题。您可以在同一本地主机上进行硬刷新,以删除任何存储的缓存。
1赞 Vinci 8/26/2021 #18

这是一个简单的例子,我先用 react 条件再用 map,在我添加了用户 ID 以确保它是唯一的&&key

 <tbody>
                                    {users &&
                                    users.map((user) => {
                                        return <tr key={user._id}>
                                            <td>{user.username}</td>
                                            <td><input
                                                name="isGoing"
                                                type="checkbox"
                                                checked={user.isEnabled}
                                                onChange={handleInputChangeNew}/></td>
                                            <td>{user.role.roleTitle} - {user.role.department.departmentName}</td>
                                            {/*<td className="text-right">
                                                    <Button>
                                                        ACTION
                                                    </Button>
                                                </td>*/}
                                        </tr>
                                    })
                                    }


                                    </tbody>
0赞 Dila Gurung 9/16/2021 #19

我不接受详细的解释,但这个答案的关键是“关键” 只需将 key 属性放在您的标签中,并确保每次迭代时都赋予它独特的价值

#ensure 键的值不会与其他键冲突

<div>
        {conversation.map(item => (
          <div key={item.id  } id={item.id}>
          </div>
        ))}
      </div>

其中对话是如下所示的数组:

  const conversation = [{id:"unique"+0,label:"OPEN"},{id:"unique"+1,label:"RESOLVED"},{id:"unique"+2,label:"ARCHIVED"},
   ]
-1赞 thinkerBOB 1/14/2022 #20

如果您正在为此错误而苦苦挣扎,列表中的每个子项都应该有一个唯一的“key”属性。

通过将索引值声明给 rendering 元素内的 key 属性来解决。

App.js 组件

import Map1 from './Map1';

const arr = [1,2,3,4,5];

const App = () => {
  return (
    <>
     
     <Map1 numb={arr} />     

    </>
  )
}

export default App

Map.js 组件

const Map1 = (props) => {

    let itemTwo = props.numb;
    let itemlist = itemTwo.map((item,index) => <li key={index}>{item}</li>)

    return (
        <>        
        <ul>
            <li style={liStyle}>{itemlist}</li>
        </ul>
        </>
    )
}

export default Map1
1赞 Atish Barua 5/3/2022 #21

你的密钥应该是唯一的,就像一个唯一的 id,你的代码应该是这样的

<div>
 {products.map(product => (
   <Product key={product.id}>
    </Product>
    ))}
  </div>
3赞 Niloy dey 5/8/2022 #22

如果我们有数组对象数据。然后我们映射以显示数据。并传递唯一 ID (key = {product.id} ),因为浏览器可以选择唯一数据。

example : [
    {
        "id": "1",
        "name": "walton glass door",
        "suplier": "walton group",
        "price": "50000",
        "quantity": "25",
        "description":"Walton Refrigerator is the Best Refrigerator brand in bv 
         Bangladesh "
    },
    {
        
        "id": "2",
        "name": "walton glass door",
        "suplier": "walton group",
        "price": "40000",
        "quantity": "5",
        "description":"Walton Refrigerator is the Best Refrigerator brand in 
         Bangladesh "
    },
}

现在,我们正在映射数据并传递唯一 ID:

{
    products.map(product => <product product={product} key={product.id} 
    </product>)
}
10赞 Basurp Patil 5/15/2022 #23

以下是使用 Key 属性很好地解释的 React 文档,键应该在父组件中定义,它不应该在子组件中使用。React 文档

enter image description here

enter image description here

评论

1赞 Sumit Sharma 5/19/2022
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接的页面发生更改,仅链接的答案可能会失效。- 从评论
2赞 user1917528 8/20/2022 #24

视觉解释。

  1. key=index(数组)的错误方式

enter image description here

如您所见,标签 3、标签 2 和标签 1 重新渲染(在“元素”面板中闪烁)。

  1. 正确的方式 key=uniqueIdenter image description here

只有顶部的新元素闪烁(重新渲染)。

0赞 Yilmaz 12/26/2022 #25

我认为在使用表(或类似示例)时,为了可重用性,应该将创建唯一键从父组件传递到子组件。

因为如果你正在创建一个表,这意味着你正在从父级传递数据。如果分配当前数据可能具有属性,但如果要在其他地方使用此表组件,则假定在已传递的每一行数据中,您都具有属性。key={row.name}namename

由于工程师将在父组件中准备数据,因此工程师应根据数据创建关键函数。

const keyFunc = (student) => {
    return student.id;
  }; 

在这种情况下,工程师知道它发送了什么数据,它知道每一行都有一个唯一的 id 属性。也许在不同的数据集中,数据集是股票价格,它没有“id”属性,而是“symbol”

 const keyFunc = (stock) => {
        return stock.symbol;
      }; 

这应该作为道具传递给子组件,以保证可重用性和唯一性。keyFunc

1赞 I.sh. 1/8/2023 #26

根据 React 文档,每一行/每一项都应该有一个唯一的键。

键帮助 React 识别哪些项目已更改、添加或删除。

就我个人而言,我更喜欢使用加密接口来生成一个随机的 UUID:
(内置在 vanilla-js 中)
crypto

const numbers = [1, 2, 3, 4, 5];

const listItems = numbers.map((number) =>
  <li key={crypto.randomUUID()}>item {number}
  </li>
);

评论

1赞 Vaibhav Nigam 3/17/2023
对于每个渲染周期,您都会调用随机化器为每个周期分配一个新键,强制它们重新渲染。这是非常低效的。相反,如果列表项未更改,则应确保分配的 ID 不会更改。li
-2赞 Bothraj P 1/10/2023 #27

当你创建一个没有特殊 key 属性的元素列表时,React 中会出现“列表中的每个子项都应该有一个唯一的 'key' prop.” 警告。必须将键分配给循环中的每个元素,以便为 React 中的元素提供稳定的身份。

我们可以将对象的 id 属性设置为唯一键。

export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 return (
<div>
    <ul>
        {posts.map(value => 
            <li key={value.id}>{value.title}</li>
        )}
    </ul>
</div>
 );}


//simple way

//if u using ant design remove the empty fragment...

//worng ans---> change to following crt ans

export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 {fields.map((field,index)=>{
return(
  <> //empty fragment
   <Row key={index}>
    <Col span={6}>hello</Col>
   </Row>
  </>
)
})}

 //correct ans
//remove the empty fragments after solve this key.prop warning problem
export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 {fields.map((field,index)=>{
return(
  <> //empty fragment
   <Row key={index}>
    <Col span={6}>hello</Col>
   </Row>
  </>
)
})}

评论

0赞 Allie Howe 1/12/2023
我可能是不正确的,但需要在迭代的最高元素上,所以如果你包含片段,它们需要更改为 .可悲的是,您不能在空片段中包含密钥。但我认为它们没有必要,因为key<React.Fragment key={index}><React.Fragment />map
0赞 Micael Mota 8/13/2023 #28

我见过很多人渲染片段,它产生了这个问题。尝试将片段更改为具有唯一<></>nullkey

0赞 Paul Bradbury 10/30/2023 #29

对于 React 官方文档

应该在里面key<li key={person}>{person}</li>


const people = [
  'Creola Katherine Johnson: mathematician',
  'Mario José Molina-Pasquel Henríquez: chemist',
  'Mohammad Abdus Salam: physicist',
  'Percy Lavon Julian: chemist',
  'Subrahmanyan Chandrasekhar: astrophysicist'
];

export default function List() {
  const listItems = people.map(person =>
    <li key={person}>{person}</li>
  );
  return <ul>{listItems}</ul>;
}


0赞 jam j 11/6/2023 #30

下面是示例代码 (App.jsx),只需将其用于您的文件

const ListItem = (props) => (
  <li>
    <input type="checkbox" />
    <p> {props.title} </p>
  </li>
);

const productList = [
  {
    id: 1,
    title: 'Shirt',
    checked: false
  },
  {
    id: 2,
    title: 'Pant',
    checked: false
  },
  {
    id: 3,
    title: 'Cap',
    checked: false
  },
]

function App(props) {
  return (
    <>
      <div>
        <ul>
          {productList.map((item) => (
            <ListItem key={item.id} title={item.title} />
          ))}
        </ul>
      </div>
    </>
  )
}

export default App
1赞 Islam Murtazaev 12/14/2023 #31

我还必须处理没有唯一键的子项的删除和添加。

因此,我最终使用 UUID 作为键,并根据元素的数量将它们包装在 useMemo 中。

  const uniqueKeys = useMemo(() =>
    data.map(_ => uuidv4()),
    [data.length]
  );

  // in render
  {data.map((item, index) => (
     <Tr key={uniqueKeys[index]}>