当前位置: 首页 > 面试题库 >

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

子车才捷
2023-03-14
问题内容

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

数组中的每个子代都应具有唯一的“键”道具。
检查TableComponent的渲染方法。

我的TableComponent渲染方法返回:

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

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

每个row输入rows都是通过具有唯一键的组件构建的:

<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>
    )
  }
});

是什么导致独特的按键道具错误?


问题答案:


遍历数组时要小心!!

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

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

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

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

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

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

  • 关键不在于性能,而在于身份(这反过来又可以带来更好的性能)。随机分配且变化的值不是身份在不知道数据建模方式的情况下,我们无法现实地[自动]提供密钥。我建议如果您没有ID,也许可以使用某种哈希函数
    使用数组时,我们已经具有内部键,但是它们是数组中的索引。当您插入新元素时,这些键是错误的。简而言之,a key应该是:

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

Using the key prop

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

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

  • 该数组是静态的,永远不会改变。
  • 永远不会过滤数组(显示数组的子集)。
  • 阵列永远不会重新排序。
  • 该阵列用作堆栈或LIFO(后进先出)。换句话说,添加只能在数组的末尾进行(即推入),而只有* 最后一项可以被删除(即弹出)。
    相反,如果我们在上面的代码片段中将添加的项目推到数组的末尾,则每个现有项目的顺序将始终是正确的。

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


 类似资料:
  • 我正在构建一个React组件,它接受一个JSON数据源并创建一个可排序表。 每个动态数据行都有一个唯一的键分配给它,但我仍然得到一个错误: 数组中的每个子项都应该有一个唯一的“键”道具。 检查TableComponent的render方法。 我的呈现方法返回: 组件是单行,并且还为其分配了唯一的键。 中的每个都是由具有唯一键的组件生成的: 而如下所示: 是什么原因导致了唯一键道具错误?

  • 我使用React来呈现数据列表,但是数据中的每一项都没有被分配id或uuid或类似于标识属性的东西。我可以使用项目索引作为关键吗?喜欢: 我所关心的是,如果页面上的其他列表也使用order索引作为子组件键,这有关系吗?钥匙应该是唯一的标识吗?

  • 编辑:下面由BlueSignal提供的链接是最适用的答案。它不仅解释了这种行为发生的原因,而且为所述问题提供了解决方案。 我有一个数组,我想确定是否所有元素都等于一个值。下面的代码似乎应该起作用,但没有。有人能解释一下吗? 任何信息都将是最受欢迎的!

  • 问题内容: 我很新,我现在真的非常困惑。 假设我有一个坐标列表,并且说我在此坐标列表中有一些双打。我一辈子都无法弄清楚如何制作一份独特的清单。通常,在Python中,我可以“欺骗”集合和其他内置函数。在Go中没有那么多。 问题答案: 您的代码中存在多个错误。最严重的是,由于您要将切片的每个特定元素与的 所有 元素进行比较,因此如果包含至少一个不同的元素,最终将附加它。而且,如果由于内部循环不会“中

  • 本文向大家介绍在React.js中深入了解JSX,包括了在React.js中深入了解JSX的使用技巧和注意事项,需要的朋友参考一下 最后,JSX只需使用createElement方法创建一个React元素。 示例 将转换为- 也可以添加自闭合标签。 大写自定义React元素 自定义的react元素必须以首字母大写命名,以便React能够区分html元素和react元素。 随着Jsx转换为React

  • 问题内容: 在处理从YQL返回的JSON时,我发现自己正在寻找一种从数组中提取所有唯一值的方法。 代码看起来有点“忙”,我想知道是否有更优雅的方法从数组中提取唯一值。 问题答案: 您可以使用indexOf来检查元素是否在数组中。 或者如果您具有唯一的ID或名称,则使用对象而不是数组:var output = {}