很多时候,我看到开发人员在呈现列表时使用项目的index作为其key。
{todos.map((todo, index) => )}
它看起来优雅,它确实摆脱了警告(这是'real'的问题,对吧?)。但是这么做有什么危险?
它可能会破坏你的应用程序并显示错误的数据
让我解释一下,key是React用来识别DOM元素的唯一东西。如果你将一个项目推入列表或删除中间的东西会发生什么?如果key与之前的相同,则React假定DOM元素表示与以前相同的组件,但这是不对的。
事实证明,当没有任何东西传递时,React使用index作为key,因为这是目前最好的猜测。此外,它会警告你,它是不理想的(它说,有点混乱的话,是的)。如果你自己提供它,React只会认为你知道你在做什么 - 记住这个例子 - 可能会导致不可预知的结果。
更好
每个这样的项目应该有一个永久性 和 _独特_ 的属性。理想情况下,应在创建项目时分配它。当然,我正在谈论一个_id_。然后我们可以通过以下方式使用它:
{todos.map((todo) => )}
注意: 首先查看项目的现有属性。他们已经有可以用作_id_的东西了。.
一种方法是将抽象中的编号移动一步。使用全局索引确保任何两个项目都有不同的_id_s。
todoCounter = 1;
function createNewTodo(text) { return { completed: false, id: todoCounter++, text }}
更好的解决方法
生产解决方案应该使用更强大的方法来处理物品的分布式创建。为此,我建议使用 shortid。它很快产生'hort non-sequential url-friendly unique'ID。代码可能如下所示:
var shortid = require('shortid');
function createNewTodo(text) { return { completed: false, id: shortid.generate(), text }}
TL;DR:为每个项目生成一个唯一的_id_,并在呈现列表时将其用作key。
更新:来自规则的例外
许多人问他们是否总是需要生成ID。其他人建议使用index作为key的用例似乎是合理的。
确实,有时产生新的ID是多余的并且可以避免。例如翻译许可条款或贡献者名单。
为了帮助您做出决定,我将这三个例子的共同点放在一起:
列表和项目是静态的 - 它们不被计算并且不改变;
列表中的项目没有ID;
该列表从不重新排序或过滤。
当 以上条件 都满足时,你可以安全地使用索引作为关键。
#### 更新2:React,Preact和*React
虽然在这篇文章中我写了关于React的问题,但问题不是排它的。在像Preact这样的类似的库中,危险也存在。但是,效果可能会有所不同。
请参阅以下StackOverflow问题,其中最后一个元素消失。另请注意Preact创建者提供的答案中的解释t, Jason Miller.
参考文献和相关文章
Dynamic Children and Keyed Fragments in React Docs
React animations for a single component, section The key is using key