key在vue和react项目中的作用_0
vue和react都使用diff算法比较新旧虚拟节点,从而更新节点。在交叉比较中,当新节点和旧节点头尾交叉比较没有结果时,旧节点数组中的key会根据新节点的key进行比较,所以至于找到对应的老节点(这里对应一个key=>indexmap映射)。如果没有找到,则认为是一个新节点。而如果没有key,那么就会通过遍历搜索找到对应的老节点,一种是map映射,一种是遍历搜索。相比较而言,地图制图速度更快。vue部分源码如下://vueprojectsrc/core/vdom/patch.js-448行//oldCh是old虚拟节点数组if(isUndef(oldKeyToIdx)){oldKeyToIdx=createKeyToOldIdx(oldCh,oldStartIdx,oldEndIdx)}if(isDef(newStartVnode.key)){//map方法获取idxInOld=oldKeyToIdx[newStartVnode.key]}else{//遍历方法获取idxInOld=findIdxInOld(newStartVnode,oldCh,oldStartIdx,oldEndIdx)}创建映射函数functioncreateKeyToOldIdx(children,beginIdx,endIdx){leti,keyconstmap={}for(i=beginIdx;i<=endIdx;i++){key=children[i].keyif(isDef(key))map[key]=i}returnmap}遍历查找//sameVnode是比较新旧节点是否相同函数findIdxInOld(node,oldCh,start,end){for(leti=start;i{{i}}
varvm=newVue({el:'#app',data:{dataList:[1,2,3,4,5]}})在上面的例子中,v-for的内容会生成如下dom节点数组,我们在每个节点上标记一个标识id:['
1
',//id:A'
2
',//id:B'
3
',//id:C'
4
',//id:D'
5
',//id:E]改变dataList数据,替换数据位置,对比改变后的数据vm.dataList=[4,1,3,5,2]//数据位置替换//如果没有key,节点位置不变,但更新节点innerText内容['
4
',//id:A'
1
',//id:B'
3
',//id:C'
5
',//id:D'
2
',//id:E]//如果有key,则交换dom节点的位置,但不更新内容//
{{i}} ['
4
',//id:D'
1
',//id:A'
3
',//id:C'
5
',//id:E'
2&l吨;/div>',//id:B]添加和删除dataList列表项vm.dataList=[3,4,5,6,7]//添加和删除数据//1.如果没有key,则节点位置保持不变。内容也更新了['
3
',//id:A'
4
',//id:B'
5
',//id:C'
6
',//id:D'
7
',//id:E]//2.如果有key,节点删除节点A和B,添加FG节点//
{{i}}['
3
',//id:C'
4
',//id:D'
5
',//id:E'
6
',//id:F'
7
',//id:G]从上面看,它没有key,使用了简单的模板,可以更有效的复用节点,diff速度也更快没有key,因为有key的节点增删改费时间。这是vue文档提到的默认模式。但这不是key的作用,而是节点可以在没有key的情况下原地复用,提高性能。这种模式会带来一些隐藏的副作用,比如可能不会产生过多的效果,或者某些节点绑定了数据(表单)状态,会出现状态错位。vue文档也说明这种模式是高效的,但是只适用于不依赖子组件状态或者临时dom状态的列表渲染输出(例如:表单输入值),但是key的作用是什么?key是每个vnode的唯一id,可以依靠key更快的获取oldVnode中对应的vnode。1.更准确,因为key没有到位复用。在sameNode函数a.key===b.key的比较中,可以避免原地使用的情况。所以它会更准确。2.更快利用key的唯一性生成map对象获取对应节点,比遍历方式更快。