你不知道的React循环渲染时为什么尽量不要把索引设置为key值?

2,198 阅读2分钟

问题分析

  • 相信大多数童鞋在使用React的时候,特别是遍历渲染元素的时候,都见过下面这个 Warning

index.js:1446 Warning: Each child in a list should have a unique "key" prop.

  • 所以我都会习惯性的给 item 指定一个 key , 而有的时候为了方便我们会直接把list 的索引指定成key,但是这样所并不被推荐,那这是为什么呢?

刨根问底

我们知道react的执行步骤一般是:

  • 用state和jsx模板生成虚拟DOM,然后用虚拟DOM生成真实的 DOM,当我们state发生变化时,render函数执行,生成新的 虚拟DOM,然后比较新旧虚拟DOM的区别,找到区别,然后直接操作DOM,改变有区别的内容,这样比传统的操作DOM,极大的提升了性能。

  • 而虚拟DOM的核心就是——Reactdiff算法,要搞清楚这个问题我们首先要来看看 diff算法

diff算法

我们从上图可以看出React 在更新虚拟DOM的时候是逐层往下的,也就是说第一层div时就有出现区别,那么对比结束,直接更新真实DOM中对应的当前节点,以此类推。

Solve the problem

  • 好! 现在我们可以来看看 这个key了,假设我们在state中有一个列表[A,B,C],在遍历渲染时用索引作为key,那么就是这样的.
A 0
B 1
C 2

如果我们执行一个操作,点击删除数组中的a, 我们的列表就是[b,c],在遍历渲染时仍然会用索引作为key,结果如下:

diff2

如图 ,我们如果不用索引为key , 程序能快速的对比出差异,反之也能对出差异,但是必须对比整个虚拟DOM, 这样,程序仍然能正常执行,只不过大大消耗了新旧虚拟DOM的对比的性能,并可能导致组件状态问题。

  • 所以,把索引设置为key值,可以吗? 可以,但是不推荐这样做,因为会大大消耗虚拟DOM的性能