React循环DOM时为什么需要添加key
一、React 渲染流程和更新流程
- react渲染流程:jsx -> 虚拟dom -> 真实dom
- react更新流程:props/state改变 -> render函数重新执行 -> 生成新的虚拟dom树 -> 新旧虚拟dom树进行diff -> 计算出差异进行更新 ->更新到真实的dom树
所以在每次更新的时候,React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI,如果一棵树参考另外一棵树进行完全比较更新,那么即使是最先进的算法,该算法的复杂程度为 O(n3),其中 n 是树中元素的数量,如果在React中使用了该算法,那么展示1000个元素所需要执行的计算量将在十亿的量级范围,这个开销太过昂贵了,React的更新性能会变得非常低效;于是React对这个算法进行了优化,将其优化成了O(n),这也就是传说中的diff算法,
二、diff 算法
diff 算法做了三处优化
- 同层节点之间相互比较,不会垮节点比较
- 不同类型的节点,产生不同的树结构
- 开发中,可以通过key来指定哪些节点在不同的渲染下保持稳定
2-1 对比不同类型的元素
-
当节点为不同的元素,React会拆卸原有的树,并且建立起新的树:当一个元素从
<a>变成<img>,从<Article>变成<Comment>,或从<Button>变成<div>都会触发一个完整的重建流程 -
当卸载一棵树时,对应的DOM节点也会被销毁,组件实例将执行 componentWillUnmount() 方法;
-
当建立一棵新的树时,对应的 DOM 节点会被创建以及插入到 DOM 中,组件实例将执行 componentWillMount()方法,紧接着 componentDidMount() 方法
-
比如下面的代码更改:React 会销毁 Comment 组件并且重新装载一个新的组件,而不会对Counter进行复用;
<div><Comment />
</div><span><Comment />
</span>
2-2 对比同一类型的元素
-
当比对两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性
-
比如下面的代码更改:通过比对这两个元素,React 知道只需要修改 DOM 元素上的 className 属性
<div className="before" title="stu" />
<div className="after" title="stu" />
- 比如下面的代码更改:当更新 style 属性时,React 仅更新有所更变的属性。通过比对这两个元素,React 知道只需要修改 DOM 元素上的 color 样式,无需修改 fontWeight。
<div style={{color="red",fontWeight:"bold"}} />
<div style={{color="green",fontWeight:"bold"}} />
- 如果是同类型的组件元素:组件会保持不变,React会更新该组件的props,并且调用componentWillReceiveProps() 和 componentWillUpdate() 方法,下一步调用 render() 方法,diff 算法将在之前的结果以及新的结果中进行递归;
参考 前端进阶面试题详细解答
2-3 对子节点递归
-
在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个mutation(改变)。
-
如果在最后插入一条数据的情况:前面两个比较是完全相同的,所以不会产生mutation,最后一个比较,产生一个mutation,将其插入到新的DOM树中即可,但是如果是在前面插入一条数据,React会对每一个子元素产生一个mutation,而不是保持
<li>星际穿越</li>和<li>盗梦空间</li>的不变;这种低效的比较方式会带来一定的性能问题,所以就得使用key来优化
后面插一条数据
<ul><li>星际穿越</li><li>盗梦空间</li></ul><ul><li>星际穿越</li><li>盗梦空间</li><li>大话西游</li></ul>前面插一条数据<ul><li>星际穿越</li><li>盗梦空间</li></ul><ul><li>大话西游</li><li>星际穿越</li><li>盗梦空间</li></ul>
三、key
要切记,在 diff 算法中,可以通过 key 来指定哪些节点在不同的渲染下保持稳定,并且要保证 key 是唯一的,不要使用随机数(随机数在下一次render时,会重新生成一个数字),也不能使用index,这都对性能是没有优化的
import React, { Component } from "react";export default class App extends Component {constructor(props) {super(props);this.state = {movies: ["星际穿越", "盗梦空间"],};}render() {return (<div><h2>电影列表</h2><ul>{this.state.movies.map((item, index) => { return <li key={item}>{item}</li>; })} </ul><button onClick={(e) => this.insertMovie()}>添加电影</button></div>);}insertMovie() {this.setState({movies: ["大话西游", ...this.state.movies],});}
}
代码解析:在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个mutation。如果在movies后面添加数据,前面两个比较是完全相同的,所以不会产生mutation;最后一个比较,产生一个mutation,将其插入到新的DOM树中即可;
如果在movies前面添加数据,React会对每一个子元素产生一个mutation,而不是保持 <li>星际穿越</li>和<li>盗梦空间</li>的不变,这种低效的比较方式会带来一定的性能问题,
当子元素(这里的li)拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素:
在下面这种场景下,key为"星际穿越"和"盗梦空间"的元素仅仅进行位移,不需要进行任何的修改; 将key为"大话西游"的元素插入到最前面的位置即可;
相关文章:
React循环DOM时为什么需要添加key
一、React 渲染流程和更新流程 react渲染流程:jsx -> 虚拟dom -> 真实domreact更新流程:props/state改变 -> render函数重新执行 -> 生成新的虚拟dom树 -> 新旧虚拟dom树进行diff -> 计算出差异进行更新 ->更新到真实的dom树 所以…...
Elasticsearch架构篇 - terms aggregation
terms aggregation 即词项分桶聚合。它是 Elasticsearch 最常用的聚合,类同于关系型数据库依据关键字段做 group。 size:返回的词项分桶数量,默认 10。阈值 65535。默认情况下,协调节点向每个分片请求 top size 数量的词项桶&…...
MySQL 的体系结构、引擎与索引
MySQL的引擎与体系结构 体系结构 连接层 最上层是一些客户端和链接服务,主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限 服务层 第二层架构主要完成大多数的核心服务功能,如SQL…...
数字IC设计需要学什么?
看到不少同学在网上提问数字IC设计如何入门,在学习过程中面临着各种各样的问题,比如书本知识艰涩难懂,有知识问题难解决,网络资源少,质量参差不齐。那么数字IC设计到底需要学什么呢? 首先来看看数字IC设计…...
五分钟搞懂POM设计模式
今天,我们来聊聊Web UI自动化测试中的POM设计模式。 为什么要用POM设计模式 前期,我们学会了使用PythonSelenium编写Web UI自动化测试线性脚本 线性脚本(以快递100网站登录举栗): import timefrom selenium import …...
面试 | 递归乘法【细节决定成败】
不用[ * ]如何使两数相乘❓一、题目明细二、思路罗列 & 代码解析1、野蛮A * B【不符合题意】2、sizeof【可借鉴】解析3、简易递归【推荐】① 解析(递归展开图)② 时间复杂度分析4、移位<<运算【有挑战性💪】① 思路顺理② 算法图解…...
【Linux】环境变量与进程优先级
文章目录🎪 进程优先级🚀1.孤儿进程🚀2.优先级查看🚀3.优先级修改🎪 环境变量🚀1.常见环境变量🚀2.环境变量获取🚀3.main中的命令行参数🎪 进程优先级 每个进程都有相应…...
RocketMQ5.0.0的Broker主从同步机制
目录 一、主从同步工作原理 1. 主从配置 2. 启动HA 二、主从同步实现机制 1. 从Broker发送连接事件 2. 主Broker接收连接事件 3. 从Broker反馈复制进度 4. ReadSocketService线程读取从Broker复制进度 5. WriteSocketService传输同步消息 6. GroupTransferService线程…...
深度学习论文: EdgeYOLO: An Edge-Real-Time Object Detector及其PyTorch实现
深度学习论文: EdgeYOLO: An Edge-Real-Time Object Detector及其PyTorch实现 EdgeYOLO: An Edge-Real-Time Object Detector PDF: https://arxiv.org/pdf/2302.07483.pdf PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://github.com/shangli…...
如何做好APP性能测试?
随着智能化生活的推进,我们生活中不可避免的要用到很多程序app。有的APP性能使用感很好,用户都愿意下载使用,而有的APP总是出现卡顿或网络延迟的情况,那必然就降低了用户的好感。所以APP性能测试对于软件开发方来说至关重要&#…...
Hive窗口函数
概述 窗口函数(window functions)也叫开窗函数、OLAP函数。 如果函数具有over子句,则它是窗口函数 窗口函数可以简单地解释为类似于聚合函数的计算函数,但是通过group by 子句组合的 常规聚合会隐藏正在聚合的各个…...
C++学习笔记(1):在默认构造函数内部使用带参数的构造函数
题目以下代码的输出是不是0:#include <unordered_map> #include <iostream>using namespace std;struct CLS{int i;CLS(int i_) :i(i_){}CLS(){CLS(0);} };int main(){CLS obj;std::cout << obj.i << endl;return 0; }结果-858993460为什么…...
Android面试题_安卓面经(23/30)设计模式源码案例
系列专栏: 《150道安卓常见面试题全解析》 安卓专栏目录见帖子 : 安卓面经_anroid面经_150道安卓基础面试题全解析 安卓系统Framework面经专栏:《Android系统Framework面试题解析大全》 安卓系统Framework面经目录详情:Android系统面经_Framework开发面经_150道面试题答案解…...
Dubbo性能调优参数以及原理
Dubbo作为一个服务治理框架,功能相对来说比较完善,性能也挺不错。但很多同学在使用dubbo的时候,只是简单的参考官方说明进行配置和应用,并没有过多的去思考一些关键参数的意义,最终做出来的效果总是差强人意,接下来我们…...
vue3全家桶之vuex和pinia持久化存储基础(二)
一.vuex数据持久化存储 这里使用的是vuex4.1.0版本,和之前的vuex3一样,数据持久化存储方案也使用 vuex-persistedstate,版本是最新的安装版本,当前可下载依赖包版本4.1.0,接下来在vue3项中安装和使用: 安装vuex-persistedstate npm i vuex-persisteds…...
LAMP架构与搭建论坛
目录 1、LAMP架构简述 2、各组件作用 3、构建LAMP平台 1.编译安装Apache httpd服务 2.编译安装mysql 3.编译安装php 4.搭建一个论坛 1、LAMP架构简述 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整台系统和相关软件,能够提供动…...
代码随想录 || 回溯算法93 78 90
Day2493.复原IP地址力扣题目链接给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 . 分隔。例如&#…...
界面组件Kendo UI for Angular——让网格数据信息显示更全面
Kendo UI致力于新的开发,来满足不断变化的需求,通过React框架的Kendo UI JavaScript封装来支持React Javascript框架。Kendo UI for Angular是专用于Angular开发的专业级Angular组件,telerik致力于提供纯粹的高性能Angular UI组件,…...
【Linux】进程状态|优先级|进程切换|环境变量
文章目录1. 运行队列和运行状态2. 进程状态3. 两种特殊的进程僵尸进程孤儿进程4. 进程优先级5. 进程切换进程特性进程切换6. 环境变量的基本概念7. PATH环境变量8. 设置和获取环境变量9. 命令行参数1. 运行队列和运行状态 💕 运行队列: 进程是如何在CP…...
合宙Air780E|FTP|内网穿透|命令测试|LuatOS-SOC接口|官方demo|学习(18):FTP命令及应用
1、FTP服务器准备 本机为win11系统,利用IIS搭建FTP服务器。 搭建方式可参考博文:windows系统搭建FTP服务器教程 windows系统搭建FTP服务器教程_程序员路遥的博客-CSDN博客_windows服务器安装ftp 设置完成后,测试FTP(已正常访问…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
