1.列表渲染为什么需要key?
虚拟DOM中key的作用:
当状态中的数据发生变化时,react会根据 [新数据] 生成 [新的虚拟DOM] ,随后react进行 [新虚拟DOM] 与 [旧虚拟DOM] 的Diffing比较;
(1)旧虚拟DOM中找到了与新虚拟DOM相同的key:
<1>若虚拟DOM中内容没变,直接使用之前的真实DOM;
<2>若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM;
(2)旧虚拟DOM中未找到与新虚拟DOM相同的key;
根据数据创建新的真实DOM,随后渲染到到页面;
- 提高渲染性能:
key
属性能够帮助 React 更快速地识别哪些列表项需要更新,从而提高渲染性能;- 避免重复渲染:如果没有指定
key
属性,React 会在每次更新列表时重新渲染所有的列表项,而不仅仅是新增、删除或更改的列表项;- 帮助 React 识别列表项:
key
属性可以帮助 React 识别每个列表项,从而使 React 能够更准确地跟踪每个列表项的状态和更新;
2.列表渲染不提供key会怎么样?
如果不提供key,React 则会无法确定某个节点是否移动了。React 只能对比相同位置的两个节点,若它们类型相同,例如均为li元素,则需要对比 props 的不同,进行 props 的打补丁。因为列表渲染通常类型都是相同的,所以在位置变动时,大多数会触发节点原地复用效果,无需担心树的销毁重建发生,原地复用在不提供 key 的时候有时候也是能正确渲染的。
注:不使用key的缺点:原地复用会使传入的 props 发生变化,导致不能利用好 React.memo 的组件缓存能力。
3.列表渲染的 key 用数组索引会怎样?
效果与不使用 key 相同,仍是将新旧节点的相同索引位置进行对比,但是控制台不会打印警告。
4.可以用index作为key吗?
<template>
<div v-for="(item, index) in list" :key="index" >{{item.name}}</div>
</template>
const list = [
{
id: 1,
name: "无敌大铁锤"
},
{
id: 2,
name: "超级小布丁"
},
{
id: 3,
name: "海绵宝宝"
},
{
id:4,
name:"皮卡丘"
}
];
现在,删除“皮卡丘”是正常的,若删除“超级小布丁”,则会出现异常。
下表为删除“超级小布丁”前的数据:
id | key | index | name |
1 | 0 | 1 | 无敌大铁锤 |
2 | 1 | 1 | 超级小布丁 |
3 | 2 | 2 | 海绵宝宝 |
4 | 3 | 3 | 皮卡丘 |
下表为删除“超级小布丁”后的数据:
id | key | index | name |
1 | 0 | 0 | 无敌大铁锤 |
3 | 1 | 1 | 海绵宝宝 |
4 | 2 | 2 | 皮卡丘 |
现在,除了 “无敌大铁锤” 之外,剩下的 “海绵宝宝”、“皮卡丘”,由于被发现与相应 key 的绑定关系有变化,所以被重新渲染,则会影响性能。若现在 list 的 item 是 select 的选项,“海绵宝宝”是选中的,且“超级小布丁”被删除了,用 index 作为 key 就会变成是 “皮卡丘”选中的了,这就产生了bug。若唯一id作为key,删除 “超级小布丁”后,剩下的元素因为与 key 的关系没有发生变化,都不会被重新渲染,就会达到提升性能的目的。最会,list 的 item 作为 select 的选项,也不会出现上面所描述的bug。
补充:
用index作为key可能会产生的问题;
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新——界面效果没问题,但效率低;
- 若结构中还包含输入类的DOM:会产生错误DOM更新——界面有问题;
5.开发中如何去选择key?
- 尽量使用每条数据的唯一标识作为key, 例如身份证号、手机号等唯一值。
- 若不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。