React源码解析18(11)------ 实现多次setState的批处理
摘要
在React中,如果涉及到了多次setState,组件render几次。setState是同步的还是异步的。这是一个很常见的面试题。
而本篇文章,就是主要实现React中,对于这部分的性能优化,我们称之为批处理。例如当我有下面的JSX。
const root = document.querySelector('#root');function App() {const [num, setNum] = useState(0)const click1 = () => {setNum(num + 1)setNum(num + 2)setNum(num + 3)}return jsx("div", {onClick: click1,children: num});
}ReactDOM.createRoot(root).render(<App />)
对于当前的点击事件来说,只有最后的setNum(num + 3)是有效的。
但是在我们之前的实现中,对于这种连续三次setState,我们的代码就要处理三次,就要经过三次beginWork,completeWork,commitWork。
那我们能不能实现出一种方式,对于这种多次setState,最终之做最后一次处理。
1.修改update相关逻辑
目前,在我们的代码里,能够让组件更新的方式,就是通过setState,触发更新。而updateQueue就是用来保存更新的内容。
function enqueueUpdate(updateQueue, update) {updateQueue.shared.pending = update
}
之前,在enqueueUpdate方法里,我们是直接进行赋值的。这没什么问题,因为之前每次赋值之后都会更新一下。
但是现在我们希望,最后只更新一次的话。我们就需要一个数据结构,可以保存多次更新的内容。这里使用的是链表结构,但在真正的React源码中,使用的是环形链表。
function enqueueUpdate(updateQueue, update) {// updateQueue.shared.pending = updatelet pending = updateQueue.shared.pending;if(pending === null) {updateQueue.shared.pending = update}else{while(pending.next != null) {pending = pending.next;}pending.next = updatepending = pending.next;}
}
OK,修改完之后,我们调用了三次setState,那么updateQueue中保存的应该是一个链表了。
在之前的processUpdateQueue方法里,也是直接更新就完了。但是现在updateQueue的结构发生了变化,所以对于processUpdateQueue,更新逻辑也要改变。
function processUpdateQueue(baseState, pendingUpdate) {const result = {memoizedState: baseState}if(pendingUpdate.next === undefined) {const action = pendingUpdate.action;//setState(() => {}) 传入方法if(typeof action === 'function'){result.memoizedState = action(baseState);}else {//setState()result.memoizedState = action;}return result}while(pendingUpdate != null) {const action = pendingUpdate.action;//setState(() => {}) 传入方法if(typeof action === 'function'){baseState = action(baseState);}else {//setState()baseState = action;}pendingUpdate = pendingUpdate.next;}result.memoizedState = baseState;return result;
}
我们需要遍历pending,将所有的更新内容返回。
2.修改workLoop循环
我们想一下,之前触发更新后,执行的机制是什么样子的。
- 更新updateQueue
- 拿到更新的updateQueue,挂载Hook上
- 执行workLoop
也就是说,每次workLoop都只能拿到当前更新的内容。
如果我希望在第一次workLoop就可以拿到所有的更新内容,并且取消后面的workLoop。
有什么方法呢?微任务!!!!
我们可以将执行workLoop的过程放在微任务里,这样执行workLoop的时候,updateQueue的链表已经生成。
同时我们用一个标志位,取消后面的workLoop执行。
当workLoop执行完成后,再将标志位置反。
let isFinished = false;
export function syncWorkLoop(root,hostRootFilber) {if(isFinished) {return;}Promise.resolve(null).then(() => {wookLoop(root,hostRootFilber);})isFinished = true;`在这里插入代码片`
}
const wookLoop = (root,hostRootFilber) => {//其他代码。。。。。isFinished = false;
}
3.修改filberHook
最后,我们只要在filberHook中触发的逻辑里,替换workLoop即可:
function disaptchState(filber, hook, action) {const update = createUpdate(action);enqueueUpdate(hook.updateQueue, update);workUpdateHook = hook;syncWorkLoop(filber.return.stateNode);
}
通过这种方式,当我执行多次setState,最终只会render一次。
相关文章:
React源码解析18(11)------ 实现多次setState的批处理
摘要 在React中,如果涉及到了多次setState,组件render几次。setState是同步的还是异步的。这是一个很常见的面试题。 而本篇文章,就是主要实现React中,对于这部分的性能优化,我们称之为批处理。例如当我有下面的JSX。…...
评测凯迪仕K70「千里眼」智能锁:不忘安全初心,便捷体验更上一层
能打败凯迪仕的,只有它自己。这是我们在体验过凯迪仕最新旗舰产品K70「千里眼」智能锁之后的感受。作为凯迪仕2023年最新旗舰机型,K70「千里眼」智能锁在配置上可以说是「机皇」般的存在。3K超高清智能锁猫眼、车规级24GHz雷达、大小双屏设计、三方可视对…...
mysql数据库root密码遗忘后,修改root密码
目录 方式一: 方式二: 2.1 也可以像我这样,普通用户登录进去后 2.2 执行如下命令,将已知的user1的加密密文更新到root中 2.3 查询数据库 2.4 用root用户登录 2.5 登录正常,但这会root登录进去后,无法…...
网络安全(黑客)快速入门~
网络安全的学习需要遵守循序渐进,由浅入深。 通常网络安全学习方法有两种: 方法1:先学习编程,然后学习Web渗透及工具使用等; 适用人群:有一定的代码基础的小伙伴 基础部分 基础部分需要学习以下内容&am…...
华为OD机试 - 数字颠倒(Java 2023 B卷 100分)
目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、Java算法源码投机取巧七、效果展示 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷&am…...
leetcode做题笔记87扰乱字符串
使用下面描述的算法可以扰乱字符串 s 得到字符串 t : 如果字符串的长度为 1 ,算法停止如果字符串的长度 > 1 ,执行下述步骤: 在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,…...
第一章 初识Linux(含VMware安装Ubuntu、CentOS、Windows、FinalShell、快照)
目录 一、 课程的介绍 1.为什么要学习Linux 2.课程的安排 3.如何学习Linux 二、操作系统概述 1.学习目标 2.计算机的硬件和软件 3.什么是操作系统 4.常见的操作系统 5.本小节的总结 三、初识Linux 1.学习目标 2.Linux的诞生 3.Linux的内核 …...
MATLAB算法实战应用案例精讲-【图像处理】OCR识别方法-CRNN
目录 OCR综述 什么是OCR OCR发展历程 OCR 常用检测方法 基于回归的方法 1) box回归...
无涯教程-PHP - preg_grep()函数
preg_grep() - 语法 array preg_grep ( string $pattern, array $input [, int $flags] ); 返回由与给定模式匹配的输入数组元素组成的数组。 如果将flag设置为PREG_GREP_INVERT,则此函数返回输入数组中与给定模式不匹配的元素。 preg_grep() - 返回值 返回使用…...
【Linux】Nginx解决跨域问题
文章目录 一、跨域问题二、解决跨域问题三、结尾 一、跨域问题 在前后端分离的项目中,前端通常运行在一个域名或端口上,而后端运行在另一个域名或端口上。当浏览器发起跨域请求时,即前端页面向后端发送请求的域名、端口或协议与当前页面的域…...
无涯教程-PHP - preg_split()函数
preg_split() - 语法 array preg_split (string pattern, string string [, int limit [, int flags]]); preg_split()函数的操作与split()完全相同,只不过正则表达式被接受为pattern的输入参数。 如果指定了可选的输入参数limit,则仅返回子字符串的限…...
B. Spreadsheets
Problem - B - Codeforces 问题描述:excel有两种情况, Rr_nCc_n:R行数C列数ZZZ(列数)行数。 对这两个进行相互转换。 细节: 准确判断这两种情况 string str; cin>>str; auto posR str.find("R"), posC st…...
matlab面向对象
一、面向对象编程 1.1 面向过程与面向对象 区别: 面向过程的核心是一系列函数,执行过程是依次使用每个函数面向对象的核心是对象(类)及其属性、方法,每个对象根据需求执行自己的方法以解决问题 对象:单个…...
01、Cannot resolve MVC View ‘xxxxx前端页面‘
Cannot resolve MVC View ‘xxxxx前端页面’ 没有找到对应的mvc的前端页面。 代码:前端这里引入了 thymeleaf 模板 解决: 需要添加 thymeleaf 的依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>s…...
时空智友企业流程化管控系统文件上传漏洞复现
0x01 产品简介 时空智友企业流程化管控系统是一个功能丰富、灵活可定制的企业管理工具。通过该系统,企业能够实现流程的自动化、协同的提升、数据的洞察和决策的优化,从而提高工作效率、管理水平和企业竞争力。 0x02 漏洞概述 时空智友企业流程化管控系…...
【已解决】Authenticator:无法添加账户请验证激活代码是否正确以及您的设备是否已为此应用启用推送通知
问题: 小米手机的Authenticator添加微软账户扫描QR码提示:无法添加账户请验证激活代码是否正确以及您的设备是否已为此应用启用推送通知 解决办法: 1、在通知管理中允许Authenticator所有通知。 2、在手机设置-账户与同步里找到谷歌基础服…...
聊聊springboot tomcat的maxHttpFormPostSize
序 本文主要研究一下spring boot tomcat的maxHttpFormPostSize参数 parseParameters tomcat-embed-core-9.0.37-sources.jar!/org/apache/catalina/connector/Request.java /*** Parse request parameters.*/protected void parseParameters() {parametersParsed true;Para…...
java并发:synchronized锁详解
背景: 在java多线程当中,我们总有遇到过多个线程操作一个共享数据时,而这个最后的代码执行结果并没有按照我们的预期一样得到正确的结果。此时我们就需要让代码执行在操作共享变量时,要等一个线程操作完毕时,另一个线程…...
Unity 之NavMeshAgent 组件(导航和路径寻找的组件)
文章目录 **作用**:**属性和方法**:**用途**:**注意事项**: NavMeshAgent 是Unity引擎中用于导航和路径寻找的组件。它可以使游戏对象在场景中自动找到可行走的路径,并在避免障碍物的情况下移动到目标位置。 以下是关于…...
装箱和拆箱
1. 概念 装箱 将值类型转换成等价的引用类型 装箱的步骤 拆箱 将一个已装箱的引用类型转换为值类型,拆箱操作需要声明拆箱后转换的类型 拆箱的步骤 1)获取已装箱的对象的地址 2)将值从堆上的对象中复制到堆栈上的值变量中 2. 总结 装箱和拆箱…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
