第十四章 DOM的Diff算法与key
React使用Diff算法来比较虚拟DOM树和真实DOM树之间的差异,并仅更新必要的部分,以提高性能。key的作用是在Diff算法中帮助React确定哪些节点已更改,哪些节点已添加或删除。
我们以案例来说明。
使用索引值和唯一ID作为key的效果
- 1、使用索引值作为key
class Person extends React.Component {state = {persons: [{id:1,name:'张三',age: 20},{id:2,name:'李四',age: 21},]}// 增加人员addPerson = () => {let {persons} = this.stateconst user = {id:persons.length + 1,name:'王麻子',age:22}persons = [user,...persons]this.setState({persons})}render(){const {persons} = this.statereturn (<div><h1>验证diff算法</h1><button onClick={this.addPerson}>增加人员</button>{persons.map((val,idx)=> {const info = "姓名:"+val.name+ "===年龄:" + val.ageconsole.log(idx,info)return (<div key={idx}>{info}</div>)})}</div>)}}// 2、将虚拟DOM渲染到页面,标签必须闭合ReactDOM.render(<Person/>, document.getElementById('app'))
以上代码我们使用的是索引值idx来作为标签的key值,渲染到页面,当我点击【增加人员】的按钮时,会在persons的状态值里面最前方插入一个新的人员信息,然后react在render到页面中去。其页面效果如下:

- 2、使用id作为key值
class Person extends React.Component {state = {persons: [{id:1,name:'张三',age: 20},{id:2,name:'李四',age: 21},]}// 增加人员addPerson = () => {let {persons} = this.stateconst user = {id:persons.length + 1,name:'王麻子',age:22}persons = [user,...persons]this.setState({persons})}render(){const {persons} = this.statereturn (<div><h1>验证diff算法</h1><button onClick={this.addPerson}>增加人员</button>{persons.map((val,idx)=> {const info = "姓名:"+val.name+ "===年龄:" + val.ageconsole.log(idx,info)return (<div key={val.id}>{info}</div>)})}</div>)}}// 2、将虚拟DOM渲染到页面,标签必须闭合ReactDOM.render(<Person/>, document.getElementById('app'))
以上代码我们使用id来作为标签的key值,但是这里的效果和我们看到的是一样的,但是在react中处理的方式是不一样的,后续我们继续讨论。

使用索引值和唯一ID作为key的区别
我们对以上案例做一下修改,我们增加一个输入框,在看看其效果。
- 1、使用索引值作为key
class Person extends React.Component {state = {persons: [{id:1,name:'张三',age: 20},{id:2,name:'李四',age: 21},]}// 增加人员addPerson = () => {let {persons} = this.stateconst user = {id:persons.length + 1,name:'王麻子',age:22}persons = [user,...persons]this.setState({persons})}render(){const {persons} = this.statereturn (<div><h1>验证diff算法</h1><button onClick={this.addPerson}>增加人员</button>{persons.map((val,idx)=> {const info = "姓名:"+val.name+ "===年龄:" + val.ageconsole.log(idx,info)return (<div key={idx}>{info} <input defaultValue={info} type="text"/></div>)})}</div>)}}// 2、将虚拟DOM渲染到页面,标签必须闭合ReactDOM.render(<Person/>, document.getElementById('app'))
直接看效果:

姓名:王麻子===年龄:22 ----输入框:姓名:张三===年龄:20
姓名:张三===年龄:20 ----输入框:姓名:李四===年龄:21
姓名:李四===年龄:21 ----输入框:姓名:李四===年龄:21
在以上效果图上我们发现了严重的错误:输入框的内容与其人员信息不一致,这是为什么呢?
- 2、使用ID作为key
class Person extends React.Component {state = {persons: [{id:1,name:'张三',age: 20},{id:2,name:'李四',age: 21},]}// 增加人员addPerson = () => {let {persons} = this.stateconst user = {id:persons.length + 1,name:'王麻子',age:22}persons = [user,...persons]this.setState({persons})}render(){const {persons} = this.statereturn (<div><h1>验证diff算法</h1><button onClick={this.addPerson}>增加人员</button>{persons.map((val,idx)=> {const info = "姓名:"+val.name+ "===年龄:" + val.ageconsole.log(idx,info)return (<div key={val.id}>{info} <input defaultValue={info} type="text"/></div>)})}</div>)}}// 2、将虚拟DOM渲染到页面,标签必须闭合ReactDOM.render(<Person/>, document.getElementById('app'))
直接看效果:

姓名:王麻子===年龄:22 ----输入框:姓名:王麻子===年龄:22
姓名:张三===年龄:20 ----输入框:姓名:张三===年龄:20
姓名:李四===年龄:21 ----输入框:姓名:李四===年龄:21
在以上效果图上我们发现了人员信息与输入框的信息一致,并没有发生什么错误,这是为什么呢?
分析索引值与ID值作为key的原理
- 分析key值是索引值时的流程

根据上图我们可以知道使用索引值作为key的时候,三条数据基本上都要生成新的DOM,而输入框的值因为与旧的虚拟DOM比较内容一致,导致与新的数据不一致的结果。
- 分析key值是ID值的流程

根据上图我们可以知道使用唯一ID作为key值时,比较第一条数据时key值就不存在需要生成新的虚拟DOM,而后面两条的key值与旧的虚拟DOM一致,可以复用旧的真实DOM且不需要生成新的DOM,减少成本,这样使得性能更好。
小总结
结果案例演示我们知道为什么遍历列表时,key最好不要用index,而是使用唯一标识,以此来减少成本,提高性能。
- 虚拟DOM中key的作用
1、简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
2、详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b. 旧虚拟DOM中未找到与新虚拟DOM相同的key,根据数据创建新的真实DOM,随后渲染到到页面
- 用index作为key可能会引发的问题
1、若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2、如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
3、注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
- 开发中如何选择key?
1、最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2、如果确定只是简单的展示数据,用index也是可以的。
相关文章:
第十四章 DOM的Diff算法与key
React使用Diff算法来比较虚拟DOM树和真实DOM树之间的差异,并仅更新必要的部分,以提高性能。key的作用是在Diff算法中帮助React确定哪些节点已更改,哪些节点已添加或删除。 我们以案例来说明。 使用索引值和唯一ID作为key的效果 1、使用索引…...
MySQL调优
MySQL调优常见的回答如何回答效果更好业务层的优化如果只能用mysql该如何优化代码层的优化SQL层面优化总结常见的回答 SQL层面的优化——创建索引,创建联合索引,减少回表。再有就是少使用函数查询。 回表指的是数据库根据索引(非主键&#…...
《Flutter进阶》flutter升级空安全遇到的一些问题及解决思路
空安全出来挺久了,由于业务需求较紧,一直没时间去升级空安全,最近花了几天去升级,发现其实升级也挺简单的,不要恐惧,没有想象中的多BUG。 flutter版本从1.22.4升到3.0.5; compileSdkVersion从1…...
最值得入手的五款骨传导耳机,几款高畅销的骨传导耳机
骨传导耳机是一种声音传导方式,主要通过颅骨、骨骼把声波传递到内耳,属于非入耳式的佩戴方式。相比传统入耳式耳机,骨传导耳机不会堵塞耳道,使用时可以开放双耳,不影响与他人的正常交流。骨传导耳机不会对耳朵产生任何…...
HashMap源码分析 (1.基础入门) 学习笔记
本章为 《HashMap全B站最细致源码分析课程》 拉钩教育HashMap 学习笔记 文章目录1. HashMap的数据结构1. 数组2. 链表3. 哈希表3.1 Hash1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。 1. 数组 在生成数组的时候数…...
6 使用强制类型转换的注意事项
概述 在C语言中,强制类型转换是通过直接转换为特定类型的方式来实现的,类似于下面的代码。 float fNumber = 66.66f; // C语言的强制类型转换 int nData = (int)fNumber; 这种方式可以在任意两个类型间进行转换,太过随意和武断,很容易带来一些难以发现的隐患和问题。C++为…...
Leetcode.939 最小面积矩形
题目链接 Leetcode.939 最小面积矩形 Rating : 1752 题目描述 给定在 xy平面上的一组点,确定由这些点组成的矩形的最小面积,其中矩形的边平行于 x 轴和 y 轴。 如果没有任何矩形,就返回 0。 示例 1: 输入࿱…...
Springboot项目快速实现过滤器功能
前言很多时候,当你以为掌握了事实真相的时间,如果你能再深入一点,你可能会发现另外一些真相。比如面向切面编程的最佳编程实践是AOP,AOP的主要作用就是可以定义切入点,并在切入点纵向织入一些额外的统一操作࿰…...
基于springboot的简历系统的实现
摘 要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,简历系统当然也不能排除在外。简历系统是以实际运用为开发背景,运用软件工程原理和开发方法,采用…...
Vue3中watch的用法
watch函数用于侦听某个值的变化,当该值发生改变后,触发对应的处理逻辑。 一、watch的基本实例 <template><div><div>{{ count }}</div><button click"changCount">更改count的值</button></div> …...
MS python学习(18)
学习Pandas.DataFrame(2) load csv(comma seperated variable) files to DataFrame and vice versa upload csv files read/write csv files load data into jupyter notebook, create a new folder and then upload the csv files into it. (CSV comma seperated variable)…...
java笔记
前言 以下是一名java初学者在自学过程中所整理的笔记,欢迎大家浏览并留言,若有错误的地方请大家指正。 java语言特性 简单性:相对于其他编程语言而言,java较为简单,例如:java不再支持多继承,C…...
对象的构造及初始化
目录 一、如何初始化对象 二、构造方法 1.概念 2.特性 三、默认初始化 四、就地初始化 总结 一、如何初始化对象 在Java方法内部定义一个局部变量的时候,我们知道必须要进行初始化。 public class Test4 {public static void main(String[] args) {//未初始化…...
Socket 读取数据
1. Socket 配置参数中添加 1.1 读取 Socket 字节时的字节序 1.2 读取数据时,单次读取最大缓存值 1.3 从 Socket 读取数据时,遵从的数据包结构协议 1.4 服务器返回数据的最大值,防止客户端内存溢出 /*** Description: Socket 配置参数*/public…...
小白的Git入门教程(一)
这是本人的git的入门过程仅供参考 先是在官网下载git版本下载链接,安装步骤可以搜索其他大神的文章然后就是创建一个属于你的git本地库首先是创建一个文件夹作为根目录,这里我创建了一个叫test_git文件夹紧接着便进去新建文件夹,点击这里的g…...
第一个Vue程序
第一个Vue程序 <body> <!--view层 变成了一个模板--> <div id"app">{{message}} </div><!--导入vue.js--> <script src"https://cdn.jsdelivr.net/npm/vue2.5.16/dist/vue.min.js"></script> <script>va…...
2023上学期学习计划
目前:根据答辩的情况来看,目前去项目组,着重写好算法是相对较优的打算,先将项目写好,之后着重提升算法水平,这学期主要啃《算法导论》与《大话数据结构》这俩本书,同时刷题量要达到160题 四月份…...
深入了解MySQL锁机制及应用场景
深入了解MySQL锁机制及应用场景锁的概述锁的分类锁的应用场景数据库事务管理多线程程序开发数据库的备份和恢复对于在线游戏等高并发应用场景锁的具体使用方法锁的应用实例总结锁的概述 MySQL锁是操作MySQL数据库时常用的一种机制。MySQL锁可以保证多个用户在同时执行读写操作…...
Java类和对象
目录 一、什么是面向对象? 二、类与对象的基本概念 1.类 2.对象 三、类的定义格式 四、类与对象的定义与使用 1.什么是实例化 2.实例化对象 3.类的使用 4.类与对象的说明 总结 一、什么是面向对象? 面向对象是一种现在最为流行的程序设计方法&a…...
aspnet053+sqlserver在线考试系统xns
目 录 基于.NET的考试系统 1 摘 要 3 前 言 4 第一章 系统概述 5 1.1 本课题的研究意义 5 1.2 本论文的目的及内容 5 第二章 在线考试系统概述 7 2.1 现行在线考试系统现状 7 2.2 电子管理平台的开发方法介绍 8 2.2.1 B/S体系结构 8 2…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
