在 Vue 中为什么不推荐用 index 做 key
具体diff解释可以看看第十题
Vue3.0中 在 patchChildren 方法中有这么一段源码
patchChildren 根据是否存在 key 进行真正的 diff 或者直接 patch(也就是直接用新的节点替换掉旧的节点) 。
-
同步头部节点
第一步的事情就是从头开始寻找相同的
vnode,然后进行patch,如果发现不是相同的节点,那么立即跳出循环。isSameVNodeType作用就是判断当前vnode类型 和vnode的key是否相等key 在
diff算法的作用,就是用来判断是否是同一个节点。 -
同步尾部节点
第二步从尾开始同前
diff经历第一步操作之后,如果发现没有 patch 完,那么立即进行第二步,从尾部开始遍历依次向前
diff。如果发现不是相同的节点,那么立即跳出循环。 -
添加新的节点
第三步如果老节点全部 patch,新节点没有被 patch 完,创建新的
vnode
-
删除多余节点
第四步如果新节点全部被 patch,老节点有剩余,那么卸载所有老节点
⭐为什么不要用index
-
性能消耗
使用 index 做 key,破坏顺序操作的时候, 因为每一个节点都找不到对应的 key,导致部分节点不能复用,所有的新
vnode都需要重新创建。当我们在前面加了一条数据时 index 顺序就会被打断,导致新节点 key 全部都改变了,所以导致我们页面上的 数据都被重新渲染了。
用唯一值作为 key 可以节约开销
-
数据错位
往 input 里面输入一些值,添加一位同学效果: 采用 index 作为 key 时,当在比较时,发现虽然文本值变了,但是当继续向下比较时发现 DOM 节点还是和原来一摸一样,就复用了,但是没想到 input 输入框残留输入的值,这时候就会出现输入的值出现错位的情况
-
解决方案
既然知道用 index 在某些情况下带来很不好的影响,那平时我们在开发当中怎么去解决这种情况呢?其实只要保证 key 唯一不变就行,一般在开发中用的比较多就是下面三种情况。
- 在开发中最好每条数据使用唯一标识固定的数据作为 key,比如后台返回的 ID,手机号,身份证号等唯一值
- 可以采用 Symbol 作为 key,Symbol 是
ES6引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
let a = Symbol('测试')
let b = Symbol('测试')
console.log(a===b)//false
- 可以采用
uuid作为 key ,uuid是 Universally Unique Identifier 的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符
⭐总结
关键词:破坏顺序-----输入类的DOM-----唯一标识的key
- 用 index 作为 key 时,在对数据进行,逆序添加,逆序删除等破坏顺序的操作时,会产生没必要的真实 DOM更新,从而导致效率低
- 用 index 作为 key 时,如果结构中包含输入类的 DOM,会产生错误的 DOM 更新
- 在开发中最好每条数据使用唯一标识固定的数据作为 key,比如后台返回的 ID,手机号,身份证号等唯一值
- 如果不存在对数据逆序添加,逆序删除等破坏顺序的操作时,仅用于渲染展示用时,使用 index 作为 key 也是可以的(但是还是不建议使用,养成良好开发习惯)。
- key作为虚拟DOM对象的唯一标识 在
diff算法中起到了至关重要的作用
\