vue和react项目中key的作用

刘鹏瑜      2022-02-12     531

关键词:

vue和react都是采用diff算法来对比新旧虚拟节点,从而更新节点。

在交叉对比中,当新节点跟旧节点头尾交叉对比没有结果时,会根据新节点的key去对比旧节点数组中的key,从而找到相应的旧节点(这里对应的是一个key=>index的map映射)。如果没有找到就认为是一个新增节点。而如果没有key,那么就会采用遍历查找的方式去找到对应的旧节点,一种一个map映射,另一种是遍历查找。相比而言,map映射速度更快。

vue部分源码如下:

//vue项目 src/core/vdom/patch.js -448行
//oldCh是一个旧虚拟节点数组
if(isUndef(oldKeyToIdx)){
    oldKeyToIdx = createKeyToOldIdx(oldCh,oldStartIdx,oldEndIdx)
}
if(isDef(newStartVnode.key)){
    //map方式获取
    idxInOld = oldKeyToIdx[newStartVnode.key]
}else {
    //遍历方式获取
    idxInOld = findIdxInOld(newStartVnode,oldCh,oldStartIdx,oldEndIdx)
}

创建map函数

function createKeyToOldIdx(children,beginIdx,endIdx){
    let i,key
    const map = {}
    for(i = beginIdx;i<=endIdx;i++){
        key = children[i].key
        if(isDef(key)) map[key] = i    
    }
    return map
}

遍历寻找

//sameVnode 是对比新旧节点是否相同的函数
function findIdxInOld(node,oldCh,start,end){
    for(let i = start;i<end;i++){
        const c = oldCh[i]
        if(isDef(c) && sameVnode(node,c)) return i    
    }
}

上面的结论是基于没有key的情况diff速度会更快。确实,这种观点没有错。没有绑定key的情况下,并且在遍历模版简单的情况下,会导致虚拟新旧节点对比更快,节点也会复用。而这种复用是就地复用,一种鸭子辩型的复用。以下为简单的例子:

<div id="app">
    <div v-for="i in dataList">{{ i }}</div>
</div>
var vm = new Vue({
    el:'#app',
    data:{
        dataList:[1,2,3,4,5]    
    }
})

以上的例子,v-for的内容会生成以下的dom节点数组,我们给每一个节点标记一个身份id:

[
    '<div>1</div>',//id:A
    '<div>2</div>',//id:B
    '<div>3</div>',//id:C
    '<div>4</div>',//id:D
    '<div>5</div>',//id:E
]

改变dataList数据,进行数据位置替换,对比改变后的数据

vm.dataList = [4,1,3,5,2]//数据位置替换
//没有key的情况,节点位置不变,但是节点innerText内容更新了
[
    '<div>4</div>',//id:A
    '<div>1</div>',//id:B
    '<div>3</div>',//id:C
    '<div>5</div>',//id:D
    '<div>2</div>',//id:E
]

//有key的情况,dom节点位置进行了交换,但是内容没有更新
// <div v-for="i in dataList" :key='i'>{{ i }}</div>
[
    '<div>4</div>',//id:D
    '<div>1</div>',//id:A
    '<div>3</div>',//id:C
    '<div>5</div>',//id:E
    '<div>2</div>',//id:B
]

增删dataList列表项

vm.dataList = [3,4,5,6,7] //数据进行增删
// 1、没有key的情况,节点位置不变,内容也更新了
[
    '<div>3</div>',//id:A
    '<div>4</div>',//id:B
    '<div>5</div>',//id:C
    '<div>6</div>',//id:D
    '<div>7</div>',//id:E
]
// 2、有key的情况,节点删除了A B节点,新增了F G节点
// <div v-for="i in dataLIST" :key='i'>{{ i }}</div>
[
    '<div>3</div>',//id:C
    '<div>4</div>',//id:D
    '<div>5</div>',//id:E
    '<div>6</div>',//id:F
    '<div>7</div>',//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对象来获取对应节点,比遍历方式更快。

diffing算法以及key值的作用(代码片段)

在react/vue中key有什么作用?内部原理是什么?一.虚拟dom中key的作用简单的来说key就是虚拟dom对象中的标识,在更新显示时key有很重要的作用原理:当状态中的数据发生改变的时候,react会根据【新数据】生成... 查看详情

你知道vue中key的作用和工作原理吗?说说你对它的理解。(代码片段)

你知道vue中key的作用和工作原理吗?说说你对它的理解。原码中找答案:src\\corelvdom\\patch.js-updateChildren()测试代码如下<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"c 查看详情

vue条件渲染,列表渲染,key的作用和原理,列表过滤,列表排序,vue监测数据原理和注意事项(代码片段)

文章目录1.条件渲染2.列表渲染3.key的作用和原理3.1index作为key的效果和问题3.1id作为key的效果(最佳)3.3两个总结4.列表过滤4.1通过watch,filter和indexOf()来实现4.2通过使用computed,filter和indexOf()来实现5.列表排序6.深度了解Vue如... 查看详情

react和vue区别以及为啥会说react适合大型项目

参考技术A都说react适合做大型项目,但是什么是大型项目呢。首先在上方已经说过,选用vue或者react作为大型项目的框架主要还是在于人,在于开发团队的统合程度那为什么还要说react更适合大型项目呢,支点是什么呢?2.react社... 查看详情

高级前端面试题目大全(代码片段)

 第1题:(滴滴、饿了么)写React/Vue项目时为什么要在列表组件中写key,其作用是什么?1.更准确因为带key就不是就地复用了,在sameNode函数a.key===b.key对比中可以避免就地复用的情况。所以会更加准确。2.更快利用key的唯一性... 查看详情

vue学习总结笔记(代码片段)

...e的class绑定样式改变数值2.条件渲染3.Vue的列表渲染4.key的作用和原理4.1index作为key的效果和问题4.2id作为key的效果(最佳)3.3面试题:react,vue中的key有什么作用?5.列表过滤5.1#region和#endregion5.2使用watch和vue中的filter方法... 查看详情

vue中使用v-for渲染数据为何要添加key属性?(原理及作用)

参考技术A在Vue中使用v-for进行列表渲染的时候,它会默认使用“就地更新”的策略。当Vue在进行列表渲染的时候,Vue会直接对已有的标签就地更新,并不会将所有的标签全部重新删除和重建,只会重新渲染数据,然后再创建新的... 查看详情

vue中key的作用

key是为每个vnode指定唯一的id,在同级vnode的Diff过程中,可以根据key快速的进行对比,来判断是否为相同节点,利用key的唯一性生成map对象来获取对应节点,比遍历方式更快,指定key后,可以保证渲染的准确性(尽可能的复用DOM元素... 查看详情

路由在 webpack + react 项目中不起作用

】路由在webpack+react项目中不起作用【英文标题】:Routingnotworkinginawebpack+reactproject【发布时间】:2021-11-2421:58:03【问题描述】:我正在使用webpack+React+react-router+typescript构建一个应用程序,但我被路由卡住了,我有两个路由,默认... 查看详情

vue中key值的作用(代码片段)

Vue中key值的作用首先v-for在列表渲染时,我们可以用v-for基于一个数组来渲染一个列表。v-for指令需要使用iteminarr形式的特殊语法来进行渲染列表,arr是源数据,<ulid="example-1"><liv-for="iteminarr":key... 查看详情

渲染一颗树(分别使用vue和react创建)

...传树形结构数组。vue通过组件递归将数据渲染出一颗树,react则通过函数递归,数据结构:treeData:[label:‘1‘,key:‘1‘,children:[label:‘1-1‘,key:‘11‘,label:‘1-2‘,key:‘12‘],label:‘2‘,key:‘ 查看详情

react的数据渲染循环key的作用

...技术A1.key是虚拟dom对象的标识,在更新显示时起到重要的作用2.当状态中的数据发生变化的时候,react会根据【新数据】生成【新的虚拟DOM】,随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则见33.当旧虚拟DOM找到... 查看详情

在react或vue中,for循环用index作为key值是好还是坏呢?

React与vue的基本实现原理是通过对比两次虚拟dom的不同然后直接操作不同的dom  当以数组的下标index作为key值时 其中一个元素发生了变化就有可能导致所有元素的key值发生改变 diff算法是比较同级之间的不同 以k... 查看详情

关于vue列表渲染key绑定index的性能问题(代码片段)

...值(index)性能的问题:React官方文档原文:“如果列表项目的顺序可能会变化,我们不建议使用索引来用作key值,因为这样做会导致性能变差,还可能引起组件状态的问题”。查阅网上的博客,确实有对Vue列表渲染key绑定索引... 查看详情

react的diffing算法(面试题)(代码片段)

...来的那个真实DOM。经典面试题:react/vue中的key有什么作用?(key的内部原理是什么?)为什么遍历列表时,key最好不要用index?虚拟DOM中key的作用简单说,key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用࿱... 查看详情

支持复杂场景的vue和react集成引用的js插件

...中使用vue的组件在react组件中,向vue组件传递具名插槽和作用域插槽,以及绑定自定义事件,以及v-model应用react本身并不支持v-model,所以需要通过model的value和setter也不需要变化在react组件动态引用vue组件,类似vue的<component/>... 查看详情

虚拟dom(vuereact)中key的作用(代码片段)

虚拟DOM中key的作用:(1)简单的说:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。(2)详细的说:当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DON】,随后React进行【新... 查看详情

vue中main.js的作用

参考技术Amain.js是项目的入口文件,项目中所有的页面都会加载main.js,所以main.js,主要有三个作用:1.实例化Vue。2.放置项目中经常会用到的插件和CSS样式。例如:网络请求插件:axios和vue-resource、图片懒加载插件:vue-lazyload3.存储全... 查看详情