有没有办法让 React 为孩子自动定义“键”?

IT技术 reactjs
2021-05-17 03:37:48

我正在学习 React,我偶然发现了“动态孩子”的这个怪癖。

带有代码示例的序言:

// Render Pass 1
<Card>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</Card>

// Render Pass 2
<Card>
  <p>Paragraph 2</p>
</Card>

在第二render()遍中,vdom diffing 的工作方式似乎是删除第二个孩子,然后将第一个孩子中的文本转换为“第 2 段”。它很快,但如果你需要状态来坚持说......第二个孩子,你会看到奇怪的事情发生!

所以 React 建议对这些标签使用“key”属性现在 vdom diffing 将毫无意外,您会看到状态在renders().

我的问题:有没有办法让 React 自行设置“键”,而不是按照他们建议的方式进行设置?

2个回答

不,那里没有。

正如您所观察到的,当没有指定键时,React 的默认行为是使用一种天真的方法就地更新组件。从功能上讲,这相当于根据元素相对于其兄弟元素的索引指定默认键。在您的示例中,这看起来像:

// Render Pass 1
<Card>
  <p key={0}>Paragraph 1</p>
  <p key={1}>Paragraph 2</p>
</Card>

// Render Pass 2
<Card>
  <p key={0}>Paragraph 2</p>
</Card>

这就是为什么您会看到第一个元素的文本被转换,但正如您所注意到的,这并不总是最佳结果。那么为什么 React 不能使用更智能的自动键呢?答案是,为了做到这一点,实际上只有两种选择,而且都不理想:

  1. 他们可以对您的应用程序的结构做出某些假设。在您的简短示例中,很明显应该根据文本内容匹配段落。但这并不一定适用于所有情况,并且很难将这种逻辑扩展到具有自定义元素、大量props、嵌套子项等的更复杂场景。

  2. 他们可以使用一种花哨的通用差异算法,但是在 React 非常认真的性能方面,这些算法可能会非常昂贵。正如关于和解的 React文档所说:

    有许多算法试图找到转换元素列表的最小操作集。Levenshtein 距离可以使用 O(n 2 ) 中的单个元素插入、删除和替换来找到最小值即使我们要使用 Levenshtein,也不会发现节点何时移动到另一个位置,并且算法的复杂性要差得多。

因此,无论哪种方式,“自动键分配”的任何好处也伴随着一系列缺点。最后,这并不值得,特别是考虑到在大多数情况下手动分配键并不是那么困难或麻烦。在同一个文档页面上进一步向下:

在实践中,找到一把钥匙并不难。大多数情况下,您要显示的元素已经有一个唯一的 id。如果不是这种情况,您可以向模型添加新的 ID 属性或散列内容的某些部分以生成密钥。请记住,密钥只需在其同级中是唯一的,而不是全局唯一的。

您可以调用React.Children.toArraywhich 自动定义键