为什么 React 不能使用 CONTENT 来自动生成密钥?



很明显,对于React中的困难算法,按键是必不可少的。但我很困惑,为什么React不能根据我们迭代的内容自动生成密钥?

我还假设项目可以共享一些相似性,或者在内容上可以完全相同,但一旦用户打开页面并以某种方式将其附加到项目上,就不可能生成密钥吗?

或者可能在那里尝试解决问题,如果是的话,如果你能分享给我,我将不胜感激。

更新

谢谢你们的回答,我学到了很多!我还想了一件事:当没有稳定的id时,我们开发人员会怎么做(例如,用户添加了一个尚未保存到DB中的项目)。在这种情况下,我们只生成id,并将其附加到对象或数组中的元素,但我们不会动态生成id,因此它会随着时间的推移保持稳定。

如果React只为渲染过程中涉及的所有数组生成id,换句话说,就是直接用于渲染函数的数组,会怎么样?

它只能在提交阶段或其他阶段执行一次。此外,我相信id可以是只读的,或者其他什么的,所以用户不能擦除id。

p.s.s当我在上面写p.s.问题时,我意识到,为数组自动生成id是行不通的,因为我错过了两件事。所有副作用反应只能在"提交"阶段进行,但不能在"渲染"阶段进行。但这不是主要问题。

主要问题是当我们在后端使用筛选或排序时。由于我们收到了一个新的数组,经过过滤的数组,我们需要为这些元素重新生成id,但基本上,这是相同的html元素,我们可以在其中更改内容以匹配过滤顺序。这与前面提到的斯拉瓦·克尼亚泽夫是一样的。

React无法生成关键帧,因为关键帧的整个点是为了帮助React在其树困难阶段跟踪元素。

例如,假设您有以下代码,其中您天真地使用内容而不是密钥的标识符:

const people = usePeople(); // [{ id: "1", name: "James"}, {id: "2", name: "William"}]
return <ul>{people.map(p => <li key={p.name}>{p.name}</li>}</ul>

上面的代码将按照您的预期运行和行为。但是,如果一个人的name发生了变化,会发生什么呢?为了理解它,让我们看看它生成的树:

ul
li(James) James
li(William) William

如果James在渲染之间变成Josh,则新树将如下所示:

ul
li(Josh) Josh
li(William) William

React将比较这两个结果,并得出以下结论:

  • li(James)将被移除
  • 添加li(Josh)

但是,如果我们将key道具设置为p.id,则新旧树将分别如下所示:

ul
li(1) James
li(2) William
ul
li(1) Josh
li(2) William

当React将两者进行比较时,它会发现James已经变成了Josh,并且只需要调整文本。

在第一个场景中,<li>组件被完全销毁,取而代之的是一个全新的组件。这两个操作都为组件运行完整的React生命周期。在第二个例子中,它保持不变,只有里面的文本发生了变化。

虽然在这种人为的场景中,第一种情况下的性能损失很小,但对于复杂的组件来说,这可能非常重要。

我相信,除非你的数据100%肯定会以一种方式排序,并且永远不会改变,否则key={index}不是一个好的密钥(我认为这就是你想要的自动生成密钥)。理想情况下,无论订单如何,你都想要每种商品都独一无二的东西。

在新的测试版react文档中有更详细的解释https://beta.reactjs.org/learn/rendering-lists#where-获取您的密钥

我认为您的意思是React可能会选择在对象上使用类似稳定哈希的东西(比如串行字符串上的sha1或其他东西)来生成唯一的密钥。我认为这在很多情况下都会起作用,甚至让我停下来思考了一会儿!你的问题实际上是一个非常好的问题,也是一个深刻的问题。

然而,它并不是在所有情况下都有效。我认为它只适用于没有方法或任何附加内容的静态对象。在JS对象上,并非所有属性都是可枚举的。散列只能发生在属性的可枚举对象上,但dev可能会将不可枚举但仍然唯一的方法附加到这些对象上。事实上,即使是可枚举的方法也不能真正可靠地序列化,它们可能是使对象唯一的原因。更不用说在涉及原型继承的情况下可靠地哈希的复杂性了。

我怀疑这也有性能方面的问题。哈希很便宜,但不便宜。大多数情况下,只需引用对象中的唯一ID就可以设置关键帧,这要便宜得多。当枚举大量对象时,这些事情很重要,因此最好听从开发人员的意见。毕竟,如果你真的想对它进行散列,那么它在userland中只有一个函数调用——当不起作用时,这就省去了开发人员的巨大困惑。想到了最小惊奇原则。

还有一个方面是,这将限制JSX的表达能力,因为它基本上允许自由形式的JS。您可能需要提供一些低级别的<React.Map>组件基元,以便react提供这种默认的key处理,这意味着您对可以做什么和不能做什么(复杂的功能链)有点约束。

相关内容

  • 没有找到相关文章

最新更新