资讯专栏INFORMATION COLUMN

写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么

eccozhou / 1136人阅读

摘要:当正在更新使用渲染的元素列表时,它默认使用就地更新的策略。如果数据项的顺序被改变,将不会移动。避免对节点就地复用需要修改的节点位置没有改变,是内容更新了,这虽然提高了复用性能,但是往往在复杂的表单会导致状态出现错位。

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM。 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个类似 Vue 1.x 的 track-by="$index"。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。

避免对节点「就地复用」

需要修改的节点位置没有改变,是内容更新了,这虽然提高了复用性能,但是往往在复杂的表单会导致状态出现错位。也不会产生过度效果

key相当于每个vnode 的唯一id,我们可以依靠key,更快更精确的知道oldVnode中对应的vnode节点。

带key就不会使用就定复用了,在sameNode函数a.key===b.key对比中可以避免就地复用的情况。

我们可以利用key的唯一性来更快获取到对应节点,比遍历更快。

什么是diff算法?

要渲染真实的DOM的开销很大,因为改变真实dom,会当值整个dom树的重绘和回流。我们需要渲染真实dom的时候往往会把生成一个虚拟节点 virtual DOM,当virtual dom某个节点的数据改变后生成一个新的Vnode,然后将Vnode和oldVnode对比,当然有不同的地方教就直接修改在真实DOM上,然后是oldVnode=Vnode

真实DOM

123

virtual DOM (虚拟DOM)

var Vnode={
    tag:"div",
    children:[{
        tag:"p",text:"123"
    }]
    
}
diff的比较方式

在同层级进行,不会跨层级比较

oldDOM

123

newDOM

2222

先对比DIV,发现两个DIV不对等

查看DIV的子元素P、SPAN,发现不对等

查看P、SPAN没有子元素,则移除P,增加SPAN

现在我们来看看在进行替换

对比节点函数
function patch(oldVnode, vnode) {
  // 对比是否相等
  if (sameVnode(oldVnode, vnode)) {
    patchVnode(oldVnode, vnode)
  } else {
    const oEl = oldVnode.el // 当前oldVnode对应的真实元素节点
    let parentEle = api.parentNode(oEl) // 父元素

    createELe(vnode) // 为vnode生成新的元素

    if (parentEle !== null) {
      api.insertBefore(parentEle, vnode.el, api.nextSibling(oEl)) // 将新的元素添加到父元素中
      api.removeChild(parentEle, oldVnode.el) // 移除以前的元素
    }
  }

  return vnode
}
判断两者是否相同函数
function sameVnode(a, b) {
  return (
    a.key === b.key && // 对比key
    a.tag === b.tag && // 对比标签名
    a.isComment === b.isComment && // 是否为注释节点
    isDef(a.data) === isDef(b.data) && // 是否定义了data,或者其他属性
    sameInputType(a, b) //判断是当时 是否type相同
  )
}

匹配规则

将Vnode的子节点Vch和oldVnode的子节点oldCh提取出来

oldCh和vCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互比较,一共有4种比较方式。如果4种比较都没匹配,如果设置了key,就会用key进行比较,在比较的过程中,变量会往中间靠,一旦StartIdx>EndIdx表明oldCh和vCh至少有一个已经遍历完了,就会结束比较。

图解

如果oldS和E匹配上了,那么真实DOM中的第一个节点会移到最后

如果oldE和S匹配上了,那么真实DOM中的最后一个节点会移到最后面,匹配上的两个指针向中间移动

如果四种匹配都没有一对成功成功的,那么遍历oldChild,S挨个和他们匹配,匹配成功就在真实dom中讲成功的节点移到最前面,如果没有成功,那么犟S对应的节点插入dom中对应的olds位置,olds和s指正向中间移动

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105965.html

相关文章

  • React

    摘要:语法是一种语法的拓展语言,在中官方也推荐使用描述用户界面,使用起来会比较快捷而且易读不是一门新的语言,可以理解为是一种语法糖,作用就是能够让我们更加直观的在中创建标签,最终还是会被编译为语法,例如我们看一段代码上面的语法最终会被编译为语法, Reatc JSX语法 jsx是一种JavaScript语法的拓展语言,在React中官方也推荐使用jsx描述用户界面,使用起来会比较快捷而且易读...

    techstay 评论0 收藏0
  • 前端 100 问:能搞懂80%的请把简历给我

    摘要:解析第题第题为什么的和的中不能做异步操作解析第题第题京东下面代码中在什么情况下会打印解析第题第题介绍下及其应用。尽量减少操作次数。解析第题第题京东快手周一算法题之两数之和给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。 引言 半年时间,几千人参与,精选大厂前端面试高频 100 题,这就是「壹题」。 在 2019 年 1 月 21 日这天,「壹题」项目正式开始,在这之后每个工...

    Scott 评论0 收藏0
  • vue组件通信全面总结

    摘要:当一个组件没有声明任何时,这里会包含所有父作用域的绑定和除外,并且可以通过传入内部组件在创建高级别的组件时非常有用。 写在前面 组件间的通信是是实际开发中非常常用的一环,如何使用对项目整体设计、开发、规范都有很实际的的作用,我在项目开发中对此深有体会,总结下vue组件间通信的几种方式,讨论下各自的使用场景 文章对相关场景预览 父->子组件间的数据传递 子->父组件间的数据传递 兄弟...

    余学文 评论0 收藏0
  • 前端开发变量命名系列 - JavaScript篇

    摘要:在写法上最常见的两种命名分别为和。下面列出了一些约定成俗的适用例子提交表单处理分页页数改变处理分页每页大小改变按下键场景二异步处理这里主要是指在写数据层服务状态管理中的命名,以及回调的命名规则。 JavaScript作为前端开发从业人员必须掌握的3大基础知识中最重要的一环,也是平是接触时间最长、写得最多的。在开发过程中必然会遇到命名的问题,你会词穷、纠结、惆怅吗?本文的出现相信能够解决...

    CoXie 评论0 收藏0
  • 前端面试题总结(js、html、小程序、React、ES6、Vue、算法、全栈热门视频资源)

    摘要:并总结经典面试题集各种算法和插件前端视频源码资源于一身的文档,优化项目,在浏览器端的层面上提升速度,帮助初中级前端工程师快速搭建项目。 本文是关注微信小程序的开发和面试问题,由基础到困难循序渐进,适合面试和开发小程序。并总结vue React html css js 经典面试题 集各种算法和插件、前端视频源码资源于一身的文档,优化项目,在浏览器端的层面上提升速度,帮助初中级前端工程师快...

    pumpkin9 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<