我正在构建一个React组件,它接受JSON数据源并创建一个可排序的表 .
每个动态数据行都有一个分配给它的唯一键,但我仍然收到以下错误:
数组中的每个子节点都应该具有唯一的“键”支柱 . 检查TableComponent的render方法 .
我的 TableComponent
render方法返回:
<table>
<thead key="thead">
<TableHeader columns={columnNames}/>
</thead>
<tbody key="tbody">
{ rows }
</tbody>
</table>
TableHeader
组件是单行,并且还为其分配了唯一键 .
rows
中的每个 row
都是使用具有唯一键的组件构建的:
<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>
)
}
});
导致唯一关键道具错误的原因是什么?
7 回答
您应该为每个孩子添加一个键 as well as each element inside children .
这样React可以处理最小的DOM更改 .
在你的代码中,每个
<TableRowItem key={item.id} data={item} columns={columnNames}/>
都试图在没有密钥的情况下渲染其中的一些孩子 .检查this example .
尝试从div中的
<b></b>
元素中删除key={i}
(并检查控制台) .在示例中,如果我们没有为
<b>
元素提供密钥,并且我们想要更新 onlyobject.city
,则React需要重新渲染整行而不是元素 .这是代码:
The answer posted by @Chris at the bottom goes into much more detail than this answer. Please take a look at https://stackoverflow.com/a/43892905/2325522
关于对帐中密钥重要性的文档:Keys
Be careful when iterating over arrays!!
一种常见的误解是,使用数组中元素的索引是一种可以接受的方法来抑制您可能熟悉的错误:
但是,在许多情况下它不是!这是 anti-pattern ,在某些情况下可以导致 unwanted behavior .
了解关键道具
React使用
key
prop来理解组件到DOM元素的关系,然后将其用于reconciliation process . 因此,密钥始终保持唯一非常重要,否则React很有可能会混淆元素并改变不正确的元素 . 同样重要的是,这些键在所有重新渲染过程中保持静态,以保持最佳性能 .话虽如此,如果已知阵列是完全静态的,则并不总是需要应用上述内容 . 但是,尽可能鼓励应用最佳实践 .
React开发人员在this GitHub issue中说:
简而言之,
key
应该是:Unique - 密钥不能与sibling component的密钥相同 .
Static - 渲染之间的密钥不应该改变 .
使用关键道具
根据上述说明,仔细研究以下样本,并尽可能尝试实施推荐的方法 .
坏(可能)
这可以说是在React中迭代数组时最常见的错误 . 这种方法在技术上并不是"wrong",如果您不知道自己在做什么,那只是...... "dangerous" . 如果您正在迭代静态数组,那么这是一种非常有效的方法(例如导航菜单中的链接数组) . 但是,如果要添加,删除,重新排序或过滤项目,则需要小心 . 在官方文档中查看detailed explanation .
在这个片段中,我们使用的是非静态数组,我们并不限制自己将其用作堆栈 . 这是一种不安全的方法(你会明白为什么) . 请注意,当我们将数组添加到数组的开头(基本上是非移位)时,每个
<input>
的值仍然存在 . 为什么?因为key
没有唯一标识每个项目 .换句话说,起初
Item 1
有key={0}
. 当我们添加第二个项目时,顶部项目变为Item 2
,然后是Item 1
作为第二个项目 . 但是,现在Item 1
已经key={1}
而不是key={0}
了 . 相反,Item 2
现在有key={0}
!!因此,React认为
<input>
元素没有改变,因为带有键0
的Item
始终位于顶部!So why is this approach only sometimes bad?
如果以某种方式过滤,重新排列或添加/删除项目,则此方法仅有风险 . 如果它总是静止的,那么使用起来非常安全 . 例如,使用此方法可以安全地迭代像
["Home", "Products", "Contact us"]
这样的导航菜单,因为您可能永远不会添加新链接或重新排列它们 .简而言之,这时你可以 safely 将索引用作
key
:数组是静态的,永远不会改变 .
永远不会过滤数组(显示数组的子集) .
数组永远不会重新排序 .
该数组用作堆栈或LIFO(后进先出) . 换句话说,添加只能在数组的末尾(即推送),只有最后一项可以删除(即弹出) .
如果我们改为在上面的代码片段中添加项目到数组的末尾,那么每个现有项目的顺序总是正确的 .
非常糟糕
虽然这种方法可能会保证密钥的唯一性,但它总是会强制响应重新呈现列表中的每个项目,即使这不是必需的 . 这是一个非常糟糕的解决方案,因为它会极大地影更不用说在
Math.random()
产生两次相同数字的情况下,不能排除键碰撞的可能性 .非常好
这可以说是best approach因为它使用了对数据集中每个项目唯一的属性 . 例如,如果
rows
包含从数据库获取的数据,则可以使用表的主键(通常是自动递增的数字) .好
这也是一个很好的方法 . 如果您的数据集不包含任何保证唯一性的数据(例如,任意数字的数组),则可能存在键冲突 . 在这种情况下,最好在迭代数据集之前为数据集中的每个项目手动生成唯一标识符 . 优选地,在安装组件时或者在接收数据集时(例如,来自
props
或来自异步API调用),为了仅执行一次,而不是每次重新呈现组件时 . 已经有一些库可以为您提供这样的密钥 . 这是一个例子:react-key-index .警告:数组或迭代器中的每个子项都应该具有唯一的“键”支柱 .
这是一个警告,因为我们要迭代的数组项需要一个独特的相似性 .
React处理迭代组件呈现为数组 .
更好的解决方法是为要迭代的数组项提供索引 . 例如:
index是React内置道具 .
只需将 unique key 添加到您的组件即可
我使用Guid为每个键修复了这个问题:生成Guid:
然后将此值分配给标记:
示例:更正密钥用法
这是一个警告,但 addressing this will make Reacts rendering much FASTER ,
这是因为
React
需要唯一标识列表中的每个项目 . 假设如果该列表的元素状态在ReactsVirtual DOM
中发生变化,则React需要确定哪个元素已更改以及DOM中需要更改的位置,以便浏览器DOM与Reacts Virtual DOM同步 .作为解决方案,只需为每个
li
标记引入key
属性 .key
应该是每个元素的唯一值 .