zoukankan      html  css  js  c++  java
  • 【实战】为什么使用v-for时必须添加唯一的key?

     01-v-for中的key

    使用v-for更新已渲染的元素列表时,默认用就地复用策略;

    列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素;


    我们在使用的使用经常会使用index(即数组的下标)来作为key,但其实这是不推荐的一种使用方法;

    举个例子

    const list = [
    {
    id: 1,
    name: 'test1',
    },
    {
    id: 2,
    name: 'test2',
    },
    {
    id: 3,
    name: 'test3',
    },
    ]
    <div v-for="(item, index) in list" :key="index" >{{item.name}}</div>

    上面这种是我们做项目中常用到的一种场景,因为不加key,vue现在直接报错,

    所以我使用index作为key;下面列举两种常见的数据更新情况。

    02-在最后一条数据后再加一条数据

    const list = [
    {
    id: 1,
    name: 'test1',
    },
    {
    id: 2,
    name: 'test2',
    },
    {
    id: 3,
    name: 'test3',
    },
    {
    id: 4,
    name: '我是在最后添加的一条数据',
    },
    ]

    此时前三条数据直接复用之前的,新渲染最后一条数据,此时用index作为key,没有任何问题;

    03-在中间插入一条数据

    const list = [
    {
    id: 1,
    name: 'test1',
    },
    {
    id: 4,
    name: '我是插队的那条数据',
    }
    {
    id: 2,
    name: 'test2',
    },
    {
    id: 3,
    name: 'test3',
    },
    ]

    此时更新渲染数据,通过index定义的key去进行前后数据的对比,发现

    之前的数据                         之后的数据

    key: 0 index: 0 name: test1 key: 0 index: 0 name: test1
    key: 1 index: 1 name: test2 key: 1 index: 1 name: 我是插队的那条数据
    key: 2 index: 2 name: test3 key: 2 index: 2 name: test2
    key: 3 index: 3 name: test3

    通过上面清晰的对比,发现除了第一个数据可以复用之前的之外,另外三条数据都需要重新渲染;


    是不是很惊奇,我明明只是插入了一条数据,怎么三条数据都要重新渲染?


    而我想要的只是新增的那一条数据新渲染出来就行了


    最好的办法是使用数组中不会变化的那一项作为key值,对应到项目中,


    即每条数据都有一个唯一的id,来标识这条数据的唯一性;使用id作为key值,

    我们再来对比一下向中间插入一条数据,此时会怎么去渲染

    之前的数据                               之后的数据

    key: 1 id: 1 index: 0 name: test1 key: 1 id: 1 index: 0 name: test1
    key: 2 id: 2 index: 1 name: test2 key: 4 id: 4 index: 1 name: 我是插队的那条数据
    key: 3 id: 3 index: 2 name: test3 key: 2 id: 2 index: 2 name: test2
    key: 3 id: 3 index: 3 name: test3

    现在对比发现只有一条数据变化了,就是id为4的那条数据,因此只要新渲染这一条数据就可以了,其他都是就复用之前的;


    同理在react中使用map渲染列表时,也是必须加key,且推荐做法也是使用id,也是这个原因;


    其实,真正的原因并不是vue和react怎么怎么,而是因为Virtual DOM 使用Diff算法实现的原因,


    下面大致从虚拟DOM的Diff算法实现的角度去解释一下


    vue和react的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设:


    1、两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
    2、同一层级的一组节点,他们可以通过唯一的id进行区分。


    基于以上这两点假设,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)。

    引用React’s diff algorithm中的例子:



    当某一层有很多相同的节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则。比如一下这个情况:

    我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:

    即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?


    所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。



    所以一句话,key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,


    其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。



    原360教育CTO小班亲授

    校招Offer月薪6000~10000+

    心动了就查看下方课程详细了解吧

    6月25日前报名,还可优惠1000哦!

    END

    就业那么难,还没有实习项目经历,来在线实习

    拿OFFER 面向大学生校招,

    是集职位介绍与推荐、职业规划、

    咨询和在线实习为一体的一站式职前教育平台。

    致力于帮助找工作、找实习的大学生

    斩获心仪的Offer,明晰职业规划。

    置顶“拿OFFFER”,我们不见不散。

  • 相关阅读:
    身体很累(0,25)
    近期安排
    石子合并问题圆形版 HRBUST 1819区间dp+环形+四边形优化
    Common Subsequence HDU 1159 最长公共子序列Longest Common Subsequence,LCS
    二维树状数组 1:单点修改,区间查询 LibreOJ 133
    c++位运算
    石子合并问题直线版 HRBUST 1818 简单区间动规
    最少拦截系统 HDU 1257 LIS最长递增子序列
    Longest Common Subsequence Again HDU 2253 LCS+位压缩
    石子合并 HYSBZ 3229 区间dp,最优二叉树问题,加西亚瓦克斯算法(GarsiaWachs)
  • 原文地址:https://www.cnblogs.com/rdaxue/p/13185887.html
Copyright © 2011-2022 走看看