为什么不推荐用 index 做 key

chatgpt/2023/9/26 13:43:56

之所以添加key属性,究其根本是因 diff算法。而在业务开发过程中特别是使用map, forEach 等遍历函数的时候往往随手就将index做为组件的key.

那么:key 到底有什么用? 当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用就地复用策略 。 这句话是什么意思?

diff算法

image.png

 简单的说就是新旧虚拟dom的比较,如果有差异就以新的为准,然后再插入的真实的dom中,重新渲染

key的作用

image.png

一句话: key的作用主要是为了更高效的对比虚拟DOM中每个节点是否是相同节点;

举个简单的例子

三胞胎战成一排,你怎么知道谁是老大?

如果老大皮了一下子,和老三换了一下位置,你又如何区分出来?

给他们挂个牌牌,写上老大、老二、老三。

这样就不会认错了。key就是这个作用

先如果说就是头铁,不加key属性的话行不行,答案是行的,但性能开销会大一些,并且会得到一个waring的提示,如下:

可以看到,一般的警告是黄色的,这里直接是红色,也可以想象出我们应该需要在这里添加key,属性来避免无谓的性能开销。
在react中可以使用key来标记一个组件,就类似我们的身份证一样,每个key唯一对应一个组件,这样在后续做diff比较的时候比如兄弟组件的位置交换,排序等操作,就可以快速定位到该组件,那就可以直接将定位到的两个组件互换即可。
如果没有给循环渲染的组件列表传入key做标的话,那就按照,"广度优先,分层比较"的diff算法特点去作比较,比较->发现不一样->删除子组件->新建子组件这样开销很大的操作。
所以在开发过程中,遇到循环渲染组件的时候都会加一个key的属性,而且你会发现子组件是无法获取key的值,因为这个key值是给react内部做标记使用,并非给开发者使用。


index作为key属性


上面看出一般我们开发过程中需要循环渲染一个组件列表,都应该加上一个key 来给react做标记,以此来减小性能上的开销,那在常见业务开发中使map, forEach中的index作为key是否可以呢?首先抛出答案:有些场景下使index做key就是个大坑。实际上这是因为作为key的值需要具有唯一性,而index作为key的话,不能百分百保证唯一的,比如遇到排序这种操作。来看个简单的例子

在这里插入图片描述

 点击我查看在线demo

可以通过上面的demo看到,使用map遍历一个数组,RenderItem组件key使用的是index,而在RenderItem中有两个部分组成,一个是展示出父组件传递过来的文案,第二部分是一个输入框。当我们在倒序展示这组数据的时候,会发现展示文案部分由AAA,BBB,CCC变为了 CCC,BBB,AAA但是输入框中的11,22,33并没有变成想象中的33,22,11。当我们将传入RenderItem组件中的key由Index变为list中的id的时候再次点击倒序按钮,就符合我们的预期了。
这是因为在用index作为key的时候,第一次传入的key为0,1,2.第二次传入的key依然还是0,1,2。但实际这时候标记key=0的组件和之前标记key=0的组件不是一个东西。但由于key一样所以react就认为两次组件是一样的,就不会将RenderItem组件全部渲染,只会将父组件传入属性变化的部分(这里就是现实父组件的文案AAA,BBB,CCC)重新渲染。而Input组件则不会重新渲染。
第二次将key换成了列表中的id,这就确定了id的唯一性,第一次传入RenderItem的key是1,2,3第二次则是3,2,1。那就确保了前后两次的id可以对应上。即第二次key为1的组件就是第一次key为1的组件。所以Inputz组件也会跟着一起重新渲染

总结
综上可以总结得到以下几点:

循环渲染React组件需要传入key依次来减少性能开销
传入的key需有唯一性,否则某些情况下就是大坑
传入的key具有不可读性,即子组件并不能读取父组件中的key
一般情况下比较两个树的不同算法复杂度都在O(n)的三次方,但在React中的diff算法是O(n)的一次方是一个线性的复杂度,具有很大的提升,当这个算法就有两个假设的前提:

组件的DOM结构相对稳定
类型相同的兄弟节点可以被唯一标识(节点位置顺序发生变化的时候)
一般在业务开发过程中如果通过接口获得的列表数组中有id就可以直接id来作为key,如果没有类似id的唯一标记字段,也可以使用 uuid 或者 shortid 第三方npm包来解决这个问题。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-5314363.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

红队打靶:FourAndSix2.01打靶思路详解(vulnhub)

目录 写在开头 第一步:主机发现与端口扫描 第二步:NFS渗透 第三步:7z压缩包的密码破解 第四步:ssh私钥登录 第五步:lessvi提权 总结与思考 写在开头 本篇博客根据大佬红队笔记的视频进行打靶,详述了…

postcss-pxtorem适配插件动态配置rootValue(根据文件路径名称,动态改变vue.config里配置的值)

项目背景:一个项目里有两个分辨率的设计稿(1920和2400),不能拆开来打包 参考: 是参考vant插件:移动端Vant组件库rem适配下大小异常的解决方案:https://github.com/youzan/vant/issues/1181 说明: 因为vue.c…

C++类与对象 - 4(初始化列表,Static成员,友元,内部类,匿名对象)

类与对象 - 4 1. 再谈构造函数1.1 构造函数体赋值1.2 初始化列表(重点)1.3 explicit关键字 2. Static成员2.1 概念2.2 特性 3. 友元3.1 友元函数3.2 友元类 4. 内部类5.匿名对象 1. 再谈构造函数 1.1 构造函数体赋值 在创建对象时,编译器通过…

目标检测算法——YOLOv5/YOLOv7改进之结合​ASPP(空洞空间卷积池化金字塔)

&#x1f496;&#x1f496;>>>加勒比海带&#xff0c;QQ2479200884<<<&#x1f496;&#x1f496; &#x1f340;&#x1f340;>>>【YOLO魔法搭配&论文投稿咨询】<<<&#x1f340;&#x1f340; ✨✨>>>学习交流 | 温澜潮…

JS 获取元素的大小(高度和宽度)

在 Javascript 中&#xff0c;使用下面3组属性可以获取元素的高度和宽度。如图所示。 元素尺寸属性说明clientWidth获取元素可视部分的宽度&#xff0c;即 css 的 width 和 padding 属性值之和&#xff0c;元素边框和滚动条不包括在内&#xff0c;也不包含任何可能的滚动区域c…

Build CUDA from Source

This is a note for Blog-1 and Blog-2: git clone gitgithub.com:TimDettmers/bitsandbytes.git cd bitsandbytes export CUDA_HOME/usr/local/cuda-12.1 && make cuda12x CUDA_VERSION121 export CUDA_HOME/usr/local/cuda-12.1 && make cuda12x_nomatmul

Thrift基础概念

Thrift基础概念 文章目录 Thrift基础概念Thrift的网络栈TransportProtocolProcessorServer Thrift 的特性不支持的特性 Thrift 的类型Base TypesSpecial TypesStructsContainersExceptionsServices Java实现Thrift实例 Thrift的网络栈 简单的Thrift网络栈图示 --------------…

【Java】String类为什么是final的

背景 面试时被问到&#xff0c;String为什么是final的&#xff1f; 回答&#xff1a;没有为什么&#xff0c;就是这么设计的。 面试官&#xff1a;回家等通知&#xff01; 解释 至于String为什么是final的&#xff0c;如下 安全性&#xff1a;如果String类不是final的&…
推荐文章