react反模式之index作为key

react反模式之index作为key

原文:Index as a key is an anti-pattern

我已经看到过很多React开发人员在渲染一个列表时使用index作为它的key

{todos.map((todo, index) => 
    <Todo {...todo}
        key={index} />
)}

这样写看起来很优雅并且确实摆脱了react的警告信息,那么这样写有危险的地方吗?


  这样会破坏你的应用让其显示出错误的数据

下面我来解释下,key是React来识别DOM元素的唯一属性。如果你往数组里面增加一些元素或者从数组中间移除一些东西会发生些什么呢?如果key属性和以前一样React会认为DOM元素表示的组件和以前是一样的,但是那是错误的。

这里我有个简单的例子来演示这个潜在的危险源码
index错误例子

事实证明,React 会用index作为默认的key的值因为这个时候React认为用index是最合理的。因此,React会警告你那样做是为达标准的(这样说看起来有点困惑. 如果你自己提供了key属性React会认为你知道自己在做啥. 记住这个例子,它可能会导致错误。

Better

列表里面的每一项都应该又一个永久并且唯一的属性,理想情况下应该在创建列表的时候分配下去. 当然我指的是id. 我们可以像下面这样使用它:

{todos.map((todo) => 
    <Todo {...todo}
        key={todo.id} />
)}

另外的实现方式是把编号递增添加到抽象方法中,使用一个全局的index来确保任何两个列表项的id不同。

todoCounter = 1;
function createNewTodo(text) {
    return {
        completed: false,
        id: todoCounter++,
        text
    }
}

Much better

一个产品化的解决方案是它应该更加健壮,能够用来创建分散的列表项. 因此我强烈推荐一个npm包shortid, 它可以快速的生成一系列‘短的 无序的 对url友好的 唯一的’ id,下面是示例代码:

var shortid = require('shortid');

function createNewTodo(text) {
    return {
        completed: false,
        id: shortid.generate(),
        text
    }
}

TL;DR: 为每个列表项生成一个唯一的id,然后在渲染列表项时作为key属性传给列表项.

References and related articles

. Dynamic Childrenand Keyed Fragments in React Docs
. Explanation from Paul O’Shannessy
. The importance of component keys in React.js
. React.js and Dynamic Children — Why the Keys are Important

阅读 5.2k

推荐阅读
之乎者也
用户专栏

技术分享专栏,欢迎吐槽

1 人关注
1 篇文章
专栏主页