我正在学习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的工作方式是删除第二个孩子,然后将第一个孩子的文本转换为&#34;第2段。&#34;这很快,但如果你需要坚持说......第二个孩子,你会发现奇怪的事情发生!
所以React建议使用"key" attribute for those tags。现在,vdom差异将是惊喜的,你会看到状态在renders()
之间得到保留。
我的问题:有没有办法让React设置&#34;键&#34;它本身而不是按照他们的建议去做?
答案 0 :(得分:18)
不,没有。
当没有指定密钥时,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不能使用更智能的自动密钥呢?答案是,为了做到这一点,实际上只有两个选择,而且都不理想:
他们可以对您的应用结构做出某些假设。在您的简短示例中,对于人类来说,段落应根据其文本内容进行匹配是显而易见的。但是在所有情况下都不一定如此,并且很难将这种逻辑扩展到更复杂的场景,包括自定义元素,大量道具,嵌套子等等。
他们可以使用一种奇特的通用差异算法,但就性能而言,这些算法非常昂贵,而React非常认真。正如React documentation on reconciliation所说:
有许多算法试图找到转换元素列表的最小操作集。使用O(n 2 )中的单个元素插入,缺失和取代,Levenshtein距离可以找到最小值。即使我们使用Levenshtein,当节点移动到另一个位置时,这并不能找到,并且算法的复杂程度要差得多。
因此,无论哪种方式,&#34;自动键分配的任何好处&#34;也有一系列的缺点。最后,它并不值得,特别是考虑到在大多数情况下手动分配密钥并不是那么困难或繁琐。从同一文档页面进一步向下:
在实践中,找到钥匙并不是很难。大多数情况下,您要显示的元素已经具有唯一ID。如果情况并非如此,您可以向模型添加新的ID属性,或者对内容的某些部分进行哈希以生成密钥。请记住,密钥只能在其兄弟姐妹中独一无二,而不是全局唯一。
答案 1 :(得分:0)
您可以调用自动定义键的 React.Children.toArray