react渲染列表中的key的作用
这个key首先是只在渲染数组列表的时候会用到。
比如经常遇到的
如上
没有key的话,会报一个错,那么,我们可不可以使用数组的index作为下标呢?
答案是不推荐。因为在数组项的顺序在插入、删除或者重新排序等操作中会发生改变,此时把索引作为key可能会产生一些微妙的bug。
像下面这种纯div渲染列表是没有问题的,用index作为key
它的列表item是div,纯渲染
我们再来看看如果列表是非受控元素的情况,把代码改造下
点击事件会触发组件重新渲染
可以看到,列表渲染出问题了,分析一下这种情况。
setState导致render,div的index不变,所以div不会重新生成,input不受state和props的控制,因此元素的状态不变,所以变化的只有受state影响的上面的{item}。
把key改为item,如下,就没有问题了
这里其实也揭露了一个问题,那就是当key变化的时候,元素会销毁重建,若key不变,则进行更新。
再用通俗的话来说,react会借助key来判断元素是最新创建的还是移动出来的,从而减少不必要的元素渲染(不必要的diff)。key属性帮助react识别唯一的组件,从而可以更高效地更新和重新渲染,key属性有助于确保组件的唯一性,是组件能够正确被复用。
注意,这里还和虚拟dom扯上关系了,要想真正了解key的作用,必须得理解react的虚拟dom以及diff。
这里先介绍一下vdom,react组件render产生vdom,然后渲染器把vdom渲染出来。state更新的时候,组件会重新render,产生新的vdom,在浏览器平台下,为了减少dom的创建,react会对两次的render结果做diff,尽量复用dom,提高性能。这就是vdom的来由。
所以key的真正作用,就是在diff过程中,新旧虚拟dom节点,使用key进行对比,而key是保存在一个map里面,使用映射能够很快的找到哪些节点是复用,哪些节点是删除还是新增,速度非常快。比虚拟dom节点全部对比一遍速度要快的多。这就是key最直观的作用,加快diff的性能。
如果不使用key的话,在对新旧虚拟dom diff的过程中就得所有节点全部对比一遍,浪费性能。没有key的情况,就是旧地复用的问题。 没有key的情况,节点位置不变,但是节点innerText内容更新了。有key的情况下,dom节点位置进行了交换,但是内容没有更新。那么这么来看,确实是有key的时候,更浪费性能一点。但是这也要分场景,只有在最简单的纯列表渲染节点中,可以不用key。但是当你的节点有交互性,或者有状态,比如上例的节点是单选的情况,这种情况就一定需要key了,否则就会出bug。或者当你想要子节点的变化,触发过渡效果时,也需要使用key。
这里也回答了一个问题,key的作用就是为了vdom节点的复用,如果用Index作为key的话,就会出现上图中的复用错误
官网中对于diff有如下规则:
- 当元素类型变化时,会销毁重建
- 当元素类型不变时,对比属性
- 当组件元素类型不变时,通过props递归判断子节点
- 递归对比子节点,当子节点是列表时,通过key和props来判断。若key一致,则进行更新,若key不一致,就销毁重建
理解React中key的作用这个问题涉及react渲染机制和diff算法,在state或props变化的情况下,会造成渲 - 掘金 (juejin.cn)