为什么 ReactJS 不为动态子项自动生成密钥?

Why doesn't ReactJS autogenerate keys for dynamic children?

在编写 ReactJS 代码时,我必须为动态子项提供密钥。例如:

render() {
  const {options} = this.state
  const availableOptions = options.map(opt => {
    return (
      <option key={opt.id} value={opt.id}>{opt.displayValue}</option>}
    )
  }

  return (
    <select onChange={this._onOptionSelect}>
      {availableOptions}
    </select>
  )
}

我明白为什么他们的钥匙在那里。但是为什么一定要给他们呢?不能只分配一个 运行 数字或 UUIDv4 或其他什么?

相关文档:http://facebook.github.io/react/docs/multiple-components.html#dynamic-children

Why doesn't ReactJS autogenerate keys for dynamic children?

确实如此,因为它需要一些东西 来识别虚拟dom 树中的元素。如果您检查生成的 html 以查找一些省略了 key 属性的动态子项,您会看到:

哪里key ∈ {0,1,2,3}

但那是未指明的行为,您应该依赖它。 出现警告是因为:

  • React 不会也确实想要对您的应用程序做出任何假设。开发人员有责任提供合适的密钥,以便可以应用所有特定于反应的优化(例如 dom 节点的重用)。
  • 他们 (Facebook) 可以随时更改未指定的默认行为,从而破坏任何依赖它的代码。

重复次数不够:不要依赖默认行为!

Tl;博士

您需要为与该元素的 data 关联的动态元素分配一个唯一键(可能是来自数据库字段或其他内容的 id),因为它会停止不必要的重新呈现.这是 React 的主要吸引力,也是它以性能着称的原因。

原因

您需要为动态子元素分配一个唯一键,因为 React virtual DOM 就是这样将该元素与 特定 数据片段相关联的。我认为一个例子可以帮助说明。

假设您有一个包含 1,000 个动态生成项目的列表。您 可以 只使用从 map 函数传入的 index 参数来为这些项目动态分配一个键。但是,如果您想更改这些项目的顺序怎么办——也许按字母顺序对它们进行排序?因为这些项目上的 key 没有绑定到特定的数据片段,而是动态生成的,所以 React 虚拟 DOM 无法跟踪这些元素。这意味着它必须重新渲染 all 1,000 个元素才能更改排序。但是,假设这些项目中的每一个都分配了一个唯一的 ID,该 ID 从数据库中填充。 virtual DOM 足够聪明,可以看到即使元素的顺序发生了变化,元素本身的数据仍然是一样的。因此,它会重新渲染 none 个元素,尽管它们的顺序已更改。

如果有任何不清楚的地方,一旦您剖析了虚拟 DOM 的真正工作原理,它就完全有意义了。本质上,虚拟 DOM 是实际 DOM 的副本。 React 比较两者并且只重新渲染实际发生变化的部分。这就是 React 获得速度的地方。因此,假设您有一个包含 3 个动态 <Item /> 组件的列表,并且您也在动态生成它们的密钥。

<Item key="1">Banana</Item>
<Item key="2">Orange</Item>
<Item key="3">Apple</Item>

现在,如果您按字母顺序重新排列这些项目,它们的键也将动态重新分配。

<Item key="1">Apple</Item>
<Item key="2">Banana</Item>
<Item key="3">Orange</Item>

此时 React 比较键 1 的内容,看看它是否与键 1 的先前渲染相比发生了变化。它已经完全重新渲染该元素。然后它检查密钥 2。它的内容也已更改,因此会重新呈现。整个列表都如此。

现在假设每个项目在数据库中都有一个与之相关联的唯一 ID,并且您将其指定为键。

<Item key="782364">Banana</Item>
<Item key="434533">Orange</Item>
<Item key="834535">Apple</Item>

现在我们按字母顺序对该列表重新排序:

<Item key="834535">Apple</Item>
<Item key="782364">Banana</Item>
<Item key="434533">Orange</Item>

此时 React 将检查键为 834535 的项目的内容是否仍然相同。嗯,内容还是一样!因此,虽然该元素的顺序不同,但它 不会 重新呈现。然后它检查键为 782364 的元素,发现它的内容也是相同的。这也适用于整个列表。

虽然在小列表中,您可能不会注意到动态生成的键与直接绑定到该元素数据的键之间的区别,但对于大列表,性能优势是 巨大。这确实是 React 的主要吸引力 - 非常智能的重新渲染。