博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
了解React.js中数组子项的唯一键
阅读量:2288 次
发布时间:2019-05-09

本文共 12535 字,大约阅读时间需要 41 分钟。

本文翻译自:

I'm building a React component that accepts a JSON data source and creates a sortable table. 我正在构建一个接受JSON数据源并创建可排序表的React组件。

Each of the dynamic data rows has a unique key assigned to it but I'm still getting an error of: 每个动态数据行都有一个分配给它的唯一键,但是我仍然遇到以下错误:

Each child in an array should have a unique "key" prop. 数组中的每个子代都应具有唯一的“键”道具。

Check the render method of TableComponent. 检查TableComponent的渲染方法。

My TableComponent render method returns: 我的TableComponent渲染方法返回:

{ rows }

The TableHeader component is a single row and also has a unique key assigned to it. TableHeader组件是单行,还为它分配了唯一的键。

Each row in rows is built from a component with a unique key: row中的每一rows都是由具有唯一键的组件构建的:

And the TableRowItem looks like this: 并且TableRowItem看起来像这样:

var TableRowItem = React.createClass({  render: function() {    var td = function() {        return this.props.columns.map(function(c) {          return {this.props.data[c]};        }, this);      }.bind(this);    return (      { td(this.props.item) }    )  }});

What is causing the unique key prop error? 是什么导致独特的按键道具错误?


#1楼

参考:


#2楼

You should add a key to each child as well as each element inside children . 您应该为每个子项以及子项中的每个元素添加一个键。

This way React can handle the minimal DOM change. 这样,React可以处理最小的DOM更改。

In your code, each <TableRowItem key={item.id} data={item} columns={columnNames}/> is trying to render some children inside them without a key. 在您的代码中,每个<TableRowItem key={item.id} data={item} columns={columnNames}/>都试图在其中创建一些没有键的子级。

Check . 检查 。

Try removing the key={i} from the <b></b> element inside the div's (and check the console). 尝试从div的<b></b>元素中删除key={i} (并检查控制台)。

In the sample, if we don't give a key to the <b> element and we want to update only the object.city , React needs to re-render the whole row vs just the element. 在示例中,如果我们不给钥匙<b>元素,我们希望更新object.city ,做出反应需要重新渲染整个行VS只是元素。

Here is the code: 这是代码:

var data = [{name:'Jhon', age:28, city:'HO'},            {name:'Onhj', age:82, city:'HN'},            {name:'Nohj', age:41, city:'IT'}           ];var Hello = React.createClass({    render: function() {      var _data = this.props.info;      console.log(_data);      return(        
{_data.map(function(object, i){ return
{[ object.name , // remove the key
{object.city} , object.age ]}
; })}
); }});React.render(
, document.body);

The answer posted by at the bottom goes into much more detail than this answer. 在底部发布的答案比该答案要详细得多。 Please take a look at 请看一下

React documentation on the importance of keys in reconciliation: 对文档进行核对: 在对帐中的重要性:


#3楼

Be careful when iterating over arrays!! 遍历数组时要小心!!

It is a common misconception that using the index of the element in the array is an acceptable way of suppressing the error you are probably familiar with: 一个常见的误解是,使用数组中元素的索引是抑制您可能熟悉的错误的可接受方法:

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

However, in many cases it is not! 但是,在许多情况下不是! This is anti-pattern that can in some situations lead to unwanted behavior . 这是一种反模式 ,在某些情况下可能导致不良行为

Understanding the key prop 了解key道具

React uses the key prop to understand the component-to-DOM Element relation, which is then used for the . React使用key道具来了解组件与DOM元素的关系,然后将其用于 。 It is therefore very important that the key always remains unique , otherwise there is a good chance React will mix up the elements and mutate the incorrect one. 因此,密钥始终保持唯一性非常重要,否则React很有可能会混淆元素并变异不正确的元素。 It is also important that these keys remain static throughout all re-renders in order to maintain best performance. 同样重要的是,这些键在所有重新渲染过程中都应保持静态 ,以保持最佳性能。

That being said, one does not always need to apply the above, provided it is known that the array is completely static. 就是说,只要知道阵列是完全静态的,就不必总是应用上述方法。 However, applying best practices is encouraged whenever possible. 但是,在可能的情况下,鼓励采用最佳实践。

A React developer said in : 一个React开发人员在 :

  • key is not really about performance, it's more about identity (which in turn leads to better performance). 关键不在于性能,而在于身份(反过来又可以带来更好的性能)。 randomly assigned and changing values are not identity 随机分配且变化的值不是身份
  • We can't realistically provide keys [automatically] without knowing how your data is modeled. 在不知道数据建模方式的情况下,我们无法现实地[自动]提供密钥。 I would suggest maybe using some sort of hashing function if you don't have ids 我建议如果您没有ID,也许使用某种哈希函数
  • We already have internal keys when we use arrays, but they are the index in the array. 使用数组时,我们已经具有内部键,但是它们是数组中的索引。 When you insert a new element, those keys are wrong. 当您插入新元素时,这些键是错误的。

In short, a key should be: 简而言之, key应该是:

  • Unique - A key cannot be identical to that of a . 唯一 -密钥不能与密钥相同。
  • Static - A key should not ever change between renders. 静态 -关键不应在渲染之间更改。

Using the key prop 使用key道具

As per the explanation above, carefully study the following samples and try to implement, when possible, the recommended approach. 根据上面的说明,请仔细研究以下示例,并在可能的情况下尝试实施推荐的方法。


Bad (Potentially) 不好(可能)

    {rows.map((row, i) => {        return 
; })}

This is arguably the most common mistake seen when iterating over an array in React. 可以说这是在React中遍历数组时最常见的错误。 This approach isn't technically "wrong" , it's just... "dangerous" if you don't know what you are doing. 从技术上讲,这种方法不是“错误”的 ,只是如果您不知道自己在做什么,则是“危险” If you are iterating through a static array then this is a perfectly valid approach (eg an array of links in your navigation menu). 如果要遍历静态数组,则这是一种完全有效的方法(例如,导航菜单中的链接数组)。 However, if you are adding, removing, reordering or filtering items, then you need to be careful. 但是,如果要添加,删除,重新排序或过滤项目,则需要小心。 Take a look at this in the official documentation. 请看官方文档中的 。

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( 
    {this.state.arr.map( (item, i) =>
    {item + " "}
    )}
); } } const Item = (props) => { return (
  • ); } ReactDOM.render(
    , document.getElementById("app"));
      

    In this snippet we are using a non-static array and we are not restricting ourselves to using it as a stack. 在此代码段中,我们使用的是非静态数组,我们并不仅限于将其用作堆栈。 This is an unsafe approach (you'll see why). 这是一种不安全的方法(您会明白为什么)。 Note how as we add items to the beginning of the array (basically unshift), the value for each <input> remains in place. 请注意,当我们将项目添加到数组的开头(基本上未移位)时,每个<input>的值都保持不变。 Why? 为什么? Because the key doesn't uniquely identify each item. 因为key不能唯一地标识每个项目。

    In other words, at first Item 1 has key={0} . 换句话说,第一Item 1首先具有key={0} When we add the second item, the top item becomes Item 2 , followed by Item 1 as the second item. 当我们添加第二个项目时,最上面的项目变成Item 2 ,然后是Item 1作为第二个项目。 However, now Item 1 has key={1} and not key={0} anymore. 但是,现在Item 1具有key={1}而不是key={0} Instead, Item 2 now has key={0} !! 相反, Item 2现在具有key={0}

    As such, React thinks the <input> elements have not changed, because the Item with key 0 is always at the top! 因此,React认为<input>元素没有改变,因为键0Item始终位于顶部!

    So why is this approach only sometimes bad? 那么,为什么这种方法有时只是不好的呢?

    This approach is only risky if the array is somehow filtered, rearranged, or items are added/removed. 仅当以某种方式过滤,重新排列或添加/删除项目时,此方法才有风险。 If it is always static, then it's perfectly safe to use. 如果它始终是静态的,则使用起来绝对安全。 For example, a navigation menu like ["Home", "Products", "Contact us"] can safely be iterated through with this method because you'll probably never add new links or rearrange them. 例如,可以安全地迭代使用["Home", "Products", "Contact us"]类的导航菜单["Home", "Products", "Contact us"]因为您可能永远不会添加新链接或重新排列它们。

    In short, here's when you can safely use the index as key : 简而言之,这是您可以安全地将索引用作key

    • The array is static and will never change. 该数组是静态的,永远不会改变。
    • The array is never filtered (display a subset of the array). 永远不会过滤数组(显示数组的子集)。
    • The array is never reordered. 阵列从不重新排序。
    • The array is used as a stack or LIFO (last in, first out). 该阵列用作堆栈或LIFO(后进先出)。 In other words, adding can only be done at the end of the array (ie push), and only the last item can ever be removed (ie pop). 换句话说,添加只能在数组的末尾(即推入)完成,并且只能删除最后一项(即弹出)。

    Had we instead, in the snippet above, pushed the added item to the end of the array, the order for each existing item would always be correct. 相反,如果我们在上面的代码段中将添加的项目到数组的末尾,则每个现有项目的顺序将始终是正确的。


    Very bad 很坏

        {rows.map((row) => {        return 
    ; })}

    While this approach will probably guarantee uniqueness of the keys, it will always force react to re-render each item in the list, even when this is not required. 尽管此方法可能会保证键的唯一性,但即使不需要时,也会始终强制做出反应以重新呈现列表中的每个项目。 This a very bad solution as it greatly impacts performance. 这是一个非常糟糕的解决方案,因为它会极大地影响性能。 Not to mention that one cannot exclude the possibility of a key collision in the event that Math.random() produces the same number twice. 更不用说在Math.random()两次产生相同数字的情况下,不能排除发生键冲突的可能性。

    Unstable keys (like those produced by Math.random() ) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components. 不稳定的键(如Math.random()产生的键)将导致不必要地重新创建许多组件实例和DOM节点,这可能导致性能下降和子组件中的状态丢失。


    Very good 很好

        {rows.map((row) => {        return 
    ; })}

    This is arguably the because it uses a property that is unique for each item in the dataset. 可以说这是因为它使用的属性对于数据集中的每个项目都是唯一的。 For example, if rows contains data fetched from a database, one could use the table's Primary Key ( which typically is an auto-incrementing number ). 例如,如果rows包含从数据库中获取的数据,则可以使用表的主键( 通常是自动递增的数字 )。

    The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. 选择键的最佳方法是使用一个字符串,该字符串唯一地标识其同级项中的列表项。 Most often you would use IDs from your data as keys 通常,您会使用数据中的ID作为键


    Good

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

    This is also a good approach. 这也是一个好方法。 If your dataset does not contain any data that guarantees uniqueness ( eg an array of arbitrary numbers ), there is a chance of a key collision. 如果您的数据集不包含任何保证唯一性的数据( 例如,任意数字的数组 ),则可能会发生键冲突。 In such cases, it is best to manually generate a unique identifier for each item in the dataset before iterating over it. 在这种情况下,最好在迭代之前为数据集中的每个项目手动生成唯一的标识符。 Preferably when mounting the component or when the dataset is received ( eg from props or from an async API call ), in order to do this only once , and not each time the component re-renders. 最好在安装组件时或在接收到数据集时( 例如从props或从异步API调用接收到),以便仅执行一次 ,而不是每次组件都重新渲染。 There are already a handful of libraries out there that can provide you such keys. 已经有少数可以为您提供此类密钥的库。 Here is one example: . 这是一个示例: 。


    #4楼

    Warning: Each child in an array or iterator should have a unique "key" prop. 警告:数组或迭代器中的每个子代都应具有唯一的“键”道具。

    This is a warning as for array items which we are going to iterate over will need a unique resemblance. 这是一个警告,因为要迭代的数组项将需要独特的相似之处。

    React handles iterating component rendering as arrays. React将迭代的组件渲染处理为数组。

    Better way to resolve this is provide index on the array items you are going to iterate over.for example: 解决此问题的更好方法是在要迭代的数组项上提供索引,例如:

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

    index is React built-in props. 索引是React内置的道具。


    #5楼

    Just add the unique key to the your Components 只需将唯一键添加到您的组件中

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

    #6楼

    I fixed this using Guid for each key like this: Generating Guid: 我为每个键使用Guid修复了此问题,如下所示:

    guid() {    return this.s4() + this.s4() + '-' + this.s4() + '-' + this.s4() + '-' +        this.s4() + '-' + this.s4() + this.s4() + this.s4();}s4() {    return Math.floor((1 + Math.random()) * 0x10000)        .toString(16)        .substring(1);}

    And then assigning this value to markers: 然后将此值分配给标记:

    {this.state.markers.map(marker => (              
    ))}

    转载地址:http://vicnb.baihongyu.com/

    你可能感兴趣的文章
    File对象功能-文件列表
    查看>>
    IO流列出目录下所有内容,带层次
    查看>>
    IO流删除带内容的目录
    查看>>
    IO流创建java文件列表
    查看>>
    Properties存取配置文件
    查看>>
    记录应用程序运行次数
    查看>>
    打印流PrintStream和PrintWriter
    查看>>
    IO流 合并流 SequenceInputStream
    查看>>
    IO流切割文件
    查看>>
    IO流-对象序列化操作流
    查看>>
    io流-多线程连接管道流
    查看>>
    RandomAccessFile可实现数据的分段写入也就是多线程下载
    查看>>
    DataInputStream与DataOutputStream用于操作基本数据类型的数据的流对象
    查看>>
    ByteArrayStream用于操作字节数组的流对象
    查看>>
    IO流-字符编码表转换示例
    查看>>
    IO流-转换流的字符编码转换-ISO-8859-1和utf-8和GBK互转
    查看>>
    基于AWS的自动化部署实践
    查看>>
    同时使用ColorKey以及顶点Alpha效果
    查看>>
    Cisco SIP支持的标准
    查看>>
    MySQL:MySQL日期数据类型、MySQL时间类型使用总结
    查看>>