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

IT技术 javascript reactjs react-jsx
2021-05-16 04:42:14

编码 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

2个回答

Tl;博士

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

原因

您需要为动态子项分配一个唯一键,因为这是 React 的虚拟 DOM将该元素与特定数据相关联的方式。我认为一个例子将有助于说明。

假设您有一个包含 1,000 个动态生成项目的列表。可以只使用indexmap函数传入参数为这些项目动态分配一个键。但是,如果您想更改这些项目的顺序 - 可能按字母顺序排序怎么办?因为key这些项目上的 不依赖于特定的数据,而是动态生成的,所以 React 虚拟 DOM 无法跟踪这些元素。这意味着它必须重新渲染所有1,000 个元素只是为了改变排序。但是,假设这些项目中的每一个都有一个分配给它的唯一 ID,该 ID 是从数据库填充的。虚拟 DOM 足够聪明,可以看到即使元素的顺序发生了变化,元素本身的数据仍然相同。因此,它不会重新渲染任何元素,尽管它们的顺序已更改。

如果其中任何一个不清楚,那么一旦您剖析了虚拟 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 会检查 key 为 834535 的项目的内容是否仍然相同。好了,内容还是一样的!因此,虽然该元素获得不同的顺序,但不会重新渲染。然后检查key为782364的元素,发现它的内容也是一样的。这也适用于整个列表。

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

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

确实如此,因为它需要一些东西来识别虚拟 dom 树中的元素。如果您检查生成的 html 的某些动态子级key省略prop,您将看到:

在此处输入图片说明

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

但是,这是不确定的行为,你应该依赖于这一点。出现警告是因为:

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

它不能经常重复:不要依赖默认行为!