您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

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

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

您应该为每个子项 子项 添加一个键。

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

在您的代码中,每个用户<TableRowItemkey={item.id}data={item}columns={columnNames}/>都试图在其中渲染一些没有键的子级。

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

在示例中,如果我们不给钥匙<b>,而我们也希望更新 在object.city起反应需要重新渲染整个行VS只是元素。

这是代码

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(
        <div>
            {_data.map(function(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(<Hello info={data} />, document.body);

遍历数组时要小心!!

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

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

但是,在许多情况下不是!这是一种反模式,在某些情况下可能导致不良行为。

React使用该key道具来了解组件与DOM元素的关系,然后将其用于对帐过程。因此,密钥始终保持唯一性非常重要,否则React很有可能会混淆元素并变异不正确的元素。同样重要的是,这些键在所有重新渲染过程中都应保持静态,以保持最佳性能

就是说,只要知道阵列是完全静态的,就不必总是应用上述方法。但是,在可能的情况下,鼓励采用最佳实践。

一个React开发人员在这个GitHub问题中说:

-密钥不能与兄弟组件的密钥相同。 -关键不应在渲染之间更改。

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

Bad (Potentially)

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

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

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

换句话说,首先Item 1具有key={0}。当我们添加第二个项目时,最上面的项目变成Item 2,然后Item 1是第二个项目。但是,现在Item 1已经key={1}没有key={0}了。相反,Item 2现在有key={0}!

因此,React认为<input>元素没有改变,因为Itemwith键0始终位于顶部!

那么为什么这种方法有时只是不好的呢?

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

简而言之,这里是您可以安全地将索引用作key

Very bad

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

尽管此方法可能会保证键的唯一性,但即使不需要时,它也会始终强制做出反应以重新呈现列表中的每个项目。这是一个非常糟糕的解决方案,因为它会极大地影响性能。更不用说在Math.random()两次产生相同数字的事件中不能排除发生按键碰撞的可能性。

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

Very good

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

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

挑选键的最佳方法是使用一个字符串,该字符串唯一地标识其同级项中的列表项。通常,您会使用数据中的ID作为键

Good

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调用或从异步API调用接收到),以便仅执行一次,而不是每次组件都重新渲染。已经有少数可以为您提供此类密钥的库。

其他 2022/1/1 18:15:25 有486人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶