详解React setState调用原理和批量更新的过程

1. React setState 调用的原理

setState目录

    • 1. React setState 调用的原理
    • 2. React setState 调用之后发生了什么?是同步还是异步?
    • 3. React中的setState批量更新的过程是什么?

在这里插入图片描述

具体的执行过程如下(源码级解析):

  • 首先调用了setState 入口函数,入口函数在这里就是充当一个分发器的角色,根据入参的不同,将其分发到不同的功能函数中去;
ReactComponent.prototype.setState = function (partialState, callback) {this.updater.enqueueSetState(this, partialState);if (callback) {this.updater.enqueueCallback(this, callback, 'setState');}
};
  • enqueueSetState 方法将新的 state 放进组件的状态队列里,并调用 enqueueUpdate 来处理将要更新的实例对象;
enqueueSetState: function (publicInstance, partialState) {// 根据 this 拿到对应的组件实例var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');// 这个 queue 对应的就是一个组件实例的 state 数组var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);queue.push(partialState);//  enqueueUpdate 用来处理当前的组件实例enqueueUpdate(internalInstance);
}
  • enqueueUpdate 方法中引出了一个关键的对象——batchingStrategy,该对象所具备的isBatchingUpdates 属性直接决定了当下是要走更新流程,还是应该排队等待;如果轮到执行,就调用 batchedUpdates 方法来直接发起更新流程。由此可以推测,batchingStrategy 或许正是 React 内部专门用于管控批量更新的对象。
function enqueueUpdate(component) {ensureInjected();// 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段if (!batchingStrategy.isBatchingUpdates) {// 若当前没有处于批量创建/更新组件的阶段,则立即更新组件batchingStrategy.batchedUpdates(enqueueUpdate, component);return;}// 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”dirtyComponents.push(component);if (component._updateBatchNumber == null) {component._updateBatchNumber = updateBatchNumber + 1;}
}

注意:batchingStrategy 对象可以理解为“锁管理器”。这里的“锁”,是指 React 全局唯一的 isBatchingUpdates 变量,isBatchingUpdates 的初始值是 false,意味着“当前并未进行任何批量更新操作”。每当 React 调用 batchedUpdate 去执行更新动作时,会先把这个锁给“锁上”(置为 true),表明“现在正处于批量更新过程中”。当锁被“锁上”的时候,任何需要更新的组件都只能暂时进入 dirtyComponents 里排队等候下一次的批量更新,而不能随意“插队”。此处体现的“任务锁”的思想,是 React 面对大量状态仍然能够实现有序分批处理的基石。

2. React setState 调用之后发生了什么?是同步还是异步?

(1)React中setState后发生了什么

在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。

在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

如果在短时间内频繁setState。React会将state的改变压入栈中,在合适的时机,批量更新state和视图,达到提高性能的效果。

(2)setState 是同步还是异步的

假如所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,多次setState),都重新vnode diff + dom修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个setState合并成一次组件更新。所以默认是异步的,但是在一些情况下是同步的。

setState 并不是单纯同步/异步的,它的表现会因调用场景的不同而不同。在源码中,通过 isBatchingUpdates 来判断setState 是先存进 state 队列还是直接更新,如果值为 true 则执行异步操作,为 false 则直接更新。

  • 异步: 在 React 可以控制的地方,就为 true,比如在 React 生命周期事件和合成事件中,都会走合并操作,延迟更新的策略。
  • 同步: 在 React 无法控制的地方,比如原生事件,具体就是在 addEventListener 、setTimeout、setInterval 等事件中,就只能同步更新。

一般认为,做异步设计是为了性能优化、减少渲染次数:

  • setState设计为异步,可以显著的提升性能。如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;最好的办法应该是获取到多个更新,之后进行批量更新;
  • 如果同步更新了state,但是还没有执行render函数,那么stateprops不能保持同步。stateprops不能保持一致性,会在开发中产生很多的问题;

3. React中的setState批量更新的过程是什么?

调用 setState 时,组件的 state 并不会立即改变, setState 只是把要修改的 state 放入一个队列, React 会优化真正的执行时机,并出于性能原因,会将 React 事件处理程序中的多次React 事件处理程序中的多次 setState 的状态修改合并成一次状态修改。 最终更新只产生一次组件及其子组件的重新渲染,这对于大型应用程序中的性能提升至关重要。

this.setState({count: this.state.count + 1    ===>    入队,[count+1的任务]
});
this.setState({count: this.state.count + 1    ===>    入队,[count+1的任务,count+1的任务]
});↓合并 state,[count+1的任务]↓执行 count+1的任务

需要注意的是,只要同步代码还在执行,“攒起来”这个动作就不会停止。(注:这里之所以多次 +1 最终只有一次生效,是因为在同一个方法中多次 setState 的合并动作不是单纯地将更新累加。比如这里对于相同属性的设置,React 只会为其保留最后一次的更新)。

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

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

相关文章

安卓13带有系统签名的应用不能正常使用webview 调用webview失败 系统应用app apk

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 android版本高一些的平台,经常会遇到一些权限安全问题,像客户的应用如果带有系统签名,会导致不能正常使用webview问题。 2.问题分析 我们log信息,可以发现下面的提示: Fo…

网络层ip协议

一.概念 ip协议主要是为了在复杂的网络环境中确定一个合适的路径来传输主机间的数据。简单来说就是用来确定主机的位置。 ip协议中的一些设备如下: 主机: 配有 IP 地址, 但是不进行路由控制的设备;路由器: 即配有 IP 地址, 又能进行路由控制;节点: 主机和路由器的统…

传统CV算法——边缘算子与图像金字塔算法介绍

边缘算子 图像梯度算子 - Sobel Sobel算子是一种用于边缘检测的图像梯度算子,它通过计算图像亮度的空间梯度来突出显示图像中的边缘。Sobel算子主要识别图像中亮度变化快的区域,这些区域通常对应于边缘。它是通过对图像进行水平和垂直方向的差分运算来…

5.2.数据结构-c/c++二叉树详解(下篇)(算法面试题)

本章所有代码请见:5.3.数据结构-c/c二叉树代码-CSDN博客 上篇:5.数据结构-c/c二叉树详解(上篇)(遍历方法,完全二叉树)-CSDN博客 目录 1 求二叉树 第k层的节点 2 查找一个节点是否在二叉树中 3 求二叉树节点的个数 4 求二叉树…

数据结构(邓俊辉)学习笔记】排序 1——快速排序:算法A

文章目录 1. 分而治之2. 轴点3. 构造轴点4. 单调性 不变性5. 实例 1. 分而治之 主题就是排序。实际上我们对于排序问题并不陌生。你应该记得在最开始的几章,我们就分别介绍过起泡排序、插入排序、选择排序以及归并排序,而在介绍散列技术时,我…

自定义TextView实现结尾加载动画

最近做项目,仿豆包和机器人对话的时候,机器人返回数据是流式返回的,需要在文本结尾添加加载动画,于是自己实现了自定义TextView控件。 源码如下: import android.content.Context import android.graphics.Canvas imp…

基于云原生向量数据库 PieCloudVector 的 RAG 实践

近年来,人工智能生成内容(AIGC)已然成为最热门的话题之一。工业界出现了各种内容生成工具,能够跨多种模态产生多样化的内容。这些主流的模型能够取得卓越表现,归功于创新的算法、模型规模的大幅扩展,以及海…

用Boot写mybatis的增删改查

一、总览 项目结构: 图一 1、JavaBean文件 2、数据库操作 3、Java测试 4、SpringBoot启动类 5、SpringBoot数据库配置 二、配置数据库 在项目资源包中新建名为application.yml的文件,如图一。 建好文件我们就要开始写…

【MySQL00】【 杂七杂八】

文章目录 一、前言二、MySQL 文件1. 参数文件2. 日志文件3. 套接字文件4. pid 文件5. 表结构定义文件6. InnoDB 存储引擎文件 二、BTree 索引排序三、InnoDB 关键特性1. 插入缓冲1.1 Insert Buffer 和 Change Buffer1.1 缓冲合并 2. 两次写2. 自适应哈希索引3. 异步IO4. 刷新邻…

江协科技STM32学习- P9 OLED调试工具

🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝​…

# VMware 共享文件

VMware tools快速安装 VMware 提供了 open-vm-tools,这是 VMware 官方推荐的开源工具包,通常不需要手动安装 VMware Tools,因为大多数 Linux 发行版(包括 Ubuntu、CentOS 等)都包含了 open-vm-tools,并且已…

Linux网络编程IO管理

网络 IO 涉及到两个系统对象,一个是用户空间调用 IO 的进程或者线程,一个是内核空间的内核系统,比如发生 IO 操作 read 时,它会经历两个阶段: 等待内核协议栈的数据准备就绪;将内核中的数据拷贝到用户态的…

Kafka【八】如何保证消息发送的可靠性、重复性、有序性

【1】消息发送的可靠性保证 对于生产者发送的数据,我们有的时候是不关心数据是否已经发送成功的,我们只要发送就可以了。在这种场景中,消息可能会因为某些故障或问题导致丢失,我们将这种情况称之为消息不可靠。虽然消息数据可能会…

Spring框架基础介绍2.0

目录 AOP概述 面向切面思想 优点: 核心原理: 使用案例: AOP 的基本概念 springAOP 实现 AspectJ 中常用的通知 Spring事物管理 数据库事务管理? spring 事务管理? Spring中的事物管理分为两种形式: 1、编程式事物管理 2、声明…

低空经济如此火爆,新手如何分一杯羹?

低空经济的火爆为新手提供了诸多参与和分一杯羹的机会。以下是一些具体的建议,帮助新手在这一领域找到切入点: 1. 了解行业概况与趋势 定义与范围:低空经济是指在3000米以下空域内进行各种有人和无人驾驶航空器活动的经济形态,涉…

dubbo的SPI机制

一.dubbo的SPI机制 SPI机制是一个服务发现机制,通过接口的全限定名找到指定目录下对应的文件,然后加载对应的实现类注册到系统中进行使用。 在Java原生跟mysql的驱动加载也使用了这个机制,但是他们只能进行全部实现类的加载(遍历…

最新HTML5中的文件详解

第5章 HTML5中的文件 5.1选择文件 可以创建一个file类型的input,添加multiple属性为true,可以实现多个文件上传。 5.1.1 选择单个文件 1.功能描述 创建file类型input元素,页面中不再有文本框,而是 选择文件 按钮,右侧是上次文件的名称&a…

数据分析面试题:客户投保问题分析

目录 0 场景描述 1 数据准备 2 问题分析 2.1 计算小微公司的平均经营时长 2.2 计算小微公司且角色为投保人,保险起期在18年的总保费 2.3 假设,DWD_CUSTOMER_REL客户关联关系表中,存在部分客户保单数很多,部分客户保单数很少的情况,此时DWD_CUSTOMER_BASE表关联,程序…

百度智能云向量数据库创新和应用实践分享

本文整理自第 15 届中国数据库技术大会 DTCC 2024 演讲《百度智能云向量数据库创新和应用实践分享》 在 IT 行业,数据库有超过 70 年的历史了。对于快速发展的 IT 行业来说,一个超过 70 年历史的技术,感觉像恐龙一样,非常稀有和少…

Anaconda Prompt 安装paddle2.6报错

bug描述 python 3.11.9 通过 pip install paddlepaddle2.6.1 安装后,运行 paddle.utils.run_check() 则出现下面的错误: 解决办法 方法一:使用paddle 3的版本 这里要注意我的python版本 方法二:使用低版本的python python3.9…