为什么不推荐用 index 做 key

news2024/11/17 7:57:08

之所以添加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.coloradmin.cn/o/816896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IP 工具

什么是IP 工具 IP 工具是用于轻松扫描和排除网络 IP 地址空间故障的网络工程工具。IP 工具使网络管理员能够审核、跟踪和监视 IP 地址、子网以及使用 IP 的设备和主机的性能。这个全面的网络工程工具集包括高级 IP 工具,如 Ping、系统资源管理器、MAC 地址解析器和…

看表情包学C语言 ——局部优先原则

🔗 【C语言趣味教程】专栏介绍👈 猛戳了解!!! Ⅰ. 作用域(Scope) 0x00 引入:什么是作用域? 变量和常量在程序中都是有作用范围的,这个范围我们称之为变量的 …

40k的offer拿到手!爽歪歪~

据说周一和就业喜报更配?快跟着我一起来看看2023上半年黑马软件测试学科的就业喜报: 从黑马软件测试学科的就业中,我们也能看到软件测试对于企业的重要性,一点也不比程序员差,他们拿到的薪资也能和程序员的高薪媲美&am…

Netty 执行了多次channelReadComplete()却没有执行ChannelRead()

[TOC](Netty 执行了多次channelReadComplete()) Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive. happy for hardess to solve denpendies.…

JAVA的回调机制、同步/异步调用

一、同步调用 同步调用是最基本的调用方式。类A的a()方法调用类B的b()方法,类A的方法需要等到B类的方法执行完成才会继续执行。如果B的方法长时间阻塞,就会导致A类方法无法正常执行下去。 二、异步调用 如果A调用B,B的执行时间比较长&#…

【Git系列】Git概述

🐳Git概述 🧊1. Git发展历史🧊 2. Git与SVN的区别🧊3. Git本地结构🧊4. 代码托管中心🪟4.1 代码托管中心是什么?🪟4.2 托管中心种类 🧊1. Git发展历史 Git的发展历史可以…

容灾独家技术揭秘:HyperBDR无主机数据同步技术

01、一对一单机热备-传统灾备方式 单机热备是一种备份解决方案,它使用两台服务器来确保高可用性,是市场上最为常见的灾备模式。 在单机热备中,一台主服务器和一台备用服务器保持同步,以确保在主服务器出现故障或宕机时可以立即切换…

【Unity】超简单特效 - 烟雾

前言: 各式各样的制造工坊常常会出现在任意类型的游戏中,铁匠铺、车间、工业建筑等等,那么如何快速且简单的实现一款可复用的烟雾特效呢,先在脑海中想象一下我们生活里常见的烟雾吧。 初步实现: 在经过简单的想象以后…

TensorFlow项目练手(三)——基于GRU股票走势预测任务

项目介绍 项目基于GRU算法通过20天的股票序列来预测第21天的数据,有些项目也可以用LSTM算法,两者主要差别如下: LSTM算法:目前使用最多的时间序列算法,是一种特殊的RNN(循环神经网络)&#xf…

JDK 8.x 微服务启动JVM参数调优实战

微服务启动JVM参数调优实战 1.1 配置JVM启动参数1.2 解释1.3 JVM参数优化思路1.3.1 调整堆内存大小1.3.2 年轻代大小1.3.3 Metaspace 大小1.3.4 栈大小1.3.5 垃圾回收器选择1.3.6 垃圾回收参数1.3.7 预分配内存 1.3.8 禁用 ResizePLAB2. 常用JVM参数 1.1 配置JVM启动参数 服务…

每日一题——重建二叉树

重建二叉树 题目描述 给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。 提示: 1.vin.length pre.length 2.pre 和…

颠倒二进制位,颠倒给定的 32 位无符号整数的二进制位。

题记: 颠倒给定的 32 位无符号整数的二进制位。 提示: 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的…

ChatPaper全流程加速科研:论文阅读+润色+优缺点分析与改进建议+审稿回复

项目设计集合(人工智能方向):助力新人快速实战掌握技能、自主完成项目设计升级,提升自身的硬实力(不仅限NLP、知识图谱、计算机视觉等领域):汇总有意义的项目设计集合,助力新人快速实…

惊喜!1行Python代码,瞬间测你工作量,分享一个统计代码行数的神器

大家好,这里是程序员晚枫。 **你想不想知道一个项目中,自己写了多少行代码?**我用今天的工具统计了一下开源项目:python-office的代码行数,竟然有21w行! 我们一起看一下怎么用最简单的方法,统…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(16)-Fiddler如何充当第三者再识AutoResponder标签-上

1.简介 Fiddler充当第三者,主要是通过AutoResponder标签在客户端和服务端之间,Fiddler抓包,然后改包,最后发送。AutoResponder这个功能可以算的上是Fiddler最实用的功能,可以让我们修改服务器端返回的数据&#xff0c…

Windows10系统还原操作

哈喽,大家好,我是雷工! 复制了下虚拟机的Win10系统,但其中有一些软件,想实现类似手机的格式化出厂操作,下面记录Windows10系统的还原操作。 一、系统环境: 虚拟机内的Windows10,64…

JavaWeb第三章:JavaScript的全面知识

目录 前言 一.JavaScript的简介 💖概念 💖学习内容 二.JavaScript的引入方式 💖内部脚本 💖外部脚本 三.JavaScript的基础语法 💖语法的书写 💖变量 ✨ 全局变量 ✨局部变量 ✨常量 &a…

vue表单筛选

目录 筛选 HTML scss* filterComp 排序 表格 自定义数据样式 inner-table 分页 删除 default-modal 自定义元素的插槽-占位符 .search-wrap {height: 60px;display: flex;align-items: center;overflow: hidden;padding: 0 20px;.selected-options-wrap {flex: 1;.…

PostgreSQL数据库中,查询时提示表不存在的解决办法

最近遇到一个奇怪的问题,以前从来没有遇到过,在postgres SCHEMA下执行select * from table1语句时,提示表不存在,而实际这个表确是存在的,只不过是在public SCHEMA下。在public SCHEMA下执行这个sql语句是没有问题的。…

主成分分析PCA算法

Principal Components Analysis 这个协方差矩阵是一个nXn的,且是对称矩阵,就会有n个特征值λ和特征向量v,每个特征向量也是n维的。第一行特征向量v对应特征值λ1 。 D(yk):表示主成分yk的方差。方差越大,说明携带的信…