react17+18 中 setState是同步还是异步更新
在类组件中使用setState,在函数式组件中使用hooks的useState。
setstate目录
- 1. 类组件
- 1.1 react 17版本
- 1.2 react 18版本
- 2、函数式组件
1. 类组件
1.1 react 17版本
参考内容:第十一篇:setState 到底是同步的,还是异步的?
彻底搞懂setState到底是同步还是异步(一)
1、在react可调度范围内的setState是异步的,并且多次setState会合并只执行最后一次,进行批量更新。
- react合成事件
- 生命周期
- 事件处理,如onClick、onChange等。
2、在react可调度范围外的setState是同步的。
- 宏任务 setTimeout、setInterval
- 微任务 .then
- 原生 js 绑定事件 document.addEventListener()
3、setState 并非真正的异步,而是通过设置全局变量 isBatchingUpdates 来判断 setState是先存进队列还是直接更新,如果值为true,则执行异步操作,如果为false,则直接更新。
isBatchingUpdates 会在 React 可以控制的地方,则为true,比如React生命周期和合成事件中,而在外部 react 无法控制的地方,比如原生事件,具体就是在 addEventListener、setTimeout、setInterval 、.then等事件中,就只能同步。
4、一般认为,做异步设计是为了性能优化,减少渲染次数。React团队的观点是:
- 保持内部一致性。如果将 state 改为同步更新,那尽管 state 的更新是同步的,但是 props不是。
- 启用并发更新,完成异步渲染。
5、案例
import React from "react";
export default class App extends React.Component{state = {count: 0}increment = () => {console.log('increment setState前的count', this.state.count) //0this.setState({count: this.state.count + 1}); //异步console.log('increment setState后的count', this.state.count) //0} //最终count变为1triple = () => {console.log('triple setState前的count', this.state.count) //1this.setState({count: this.state.count + 1});this.setState({count: this.state.count + 1});this.setState({count: this.state.count + 1});//异步,且合并console.log('triple setState后的count', this.state.count) //1} //最终count变为 2reduce = () => {setTimeout(() => {console.log('reduce setState前的count', this.state.count) //2this.setState({count: this.state.count - 1});//同步 count变为 1console.log('reduce setState后的count', this.state.count) //1},0);}render(){return <div><button onClick={this.increment}>点我增加</button><button onClick={this.triple}>点我增加三倍</button><button onClick={this.reduce}>点我减少</button></div>}
}
接着我把组件挂载到 DOM 上:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";const rootElement = document.getElementById("root");ReactDOM.render(<React.StrictMode><App /></React.StrictMode>,rootElement
);
此时浏览器里渲染出来的是如下图所示的三个按钮:
此时有个问题,若从左到右依次点击每个按钮,控制台的输出会是什么样的?

1.2 react 18版本
参考内容:彻底搞懂setState到底是同步还是异步(二)
React18版本引入了自动批处理功能,批处理是指,当 React 在一个单独的重渲染事件中批量处理多个状态更新以此实现优化性能。如果没有自动批处理的话,我们仅能够在 React 事件处理程序中批量更新。在 React 18 之前,默认情况下 promise、setTimeout、原生应用的事件处理程序以及任何其他事件中的更新都不会被批量处理;但现在,这些更新内容都会被自动批处理。
1、在react18中setTimeout里的setState也是异步的批量处理了,都是setTimeout 中的批处理明显落后外部的批处理。
上面代码在react18中的结果:0 0 1 1 2 2.
2、案例
import React from 'react';
import './App.css';class AppClass extends React.Component {state = {count: 0,};handleClick = () => {this.setState({ count: 1 });console.log('count: ', this.state.count); //0this.setState({ count: 2 });console.log('count: ', this.state.count); //0//异步,合并,count的值变为2setTimeout(() => {this.setState({ count: 3 });console.log('count: ', this.state.count); //2this.setState({ count: 4 });console.log('count: ', this.state.count); //2}, 0);//异步,合并,count的值变为4};render() {return (<div className='App'><button onClick={this.handleClick}>count = {this.state.count}</button></div>);}
}export default AppClass;
react 18的控制台打印结果:

react 17的打印结果:

对比下结果:
- 前两次的结果相同,都是0,证明这块是跟 v17 中一样的,都是异步
- 后两次结果不一样,v17中是同步更新的,所以每次setState 后都可以立即获取到更新后的值,但v18 中打印的是两个2 ,说明是异步更新的,只是这个异步更新跟setTimeout 外部的不在一个批中,setTimeout 中的批处理明显落后外部的批处理。
页面会渲染几次? (执行setState会重新渲染页面)
- react17中在setTimeout外会合并渲染一次,在setTimeout中是同步的,会渲染两次,总共页面会渲染三次。
- react18中在setTimeout外会合并渲染一次,在setTimeout中式异步的,进行自动批处理,会渲染一次,总共页面会渲染两次。
2、函数式组件
参考内容:彻底搞懂setState到底是同步还是异步(三)
函数式组件中使用hooks的useState。
1、react 17:由于闭包输出的内容全部是count初始值。在setTimeout外部是异步批处理,在setTimeout内部不是批处理,与react 17中的类组件是否批处理一样。
2、react 18:由于闭包输出的内容全部是count初始值。在setTimeout外部是异步批处理,在setTimeout内部也是自动批处理,与react 18中的类组件是否批处理一样。
3、案例
把上述题目改造成hooks的形式:
import { useState } from 'react';
import './App.css';function App() {const [count, setCount] = useState(0);const handle = () => {setCount(1);console.log('count: ', count); //0setCount(2);console.log('count: ', count); //0setTimeout(() => {setCount(3);console.log('count: ', count); //0setCount(4);console.log('count: ', count); //0}, 0);};return (<><div className='App'><button onClick={handle}>count is {count}</button></div></>);
}export default App;
react 17的执行结果:

react 18的执行结果:

输出结果都是0,看似都是在批处理,为了能更清楚的看到 React 的渲染行为,修改下上边的代码,在每次渲染都都打印下当前的 count值,添加如下代码:
useEffect(() => {console.log('render: 此时的count: ', count);});
再次查看输出结果:


分析下:
- 在 React 17 下,render 打印了 3 次,说明组件重新渲染了 3 次,回顾下当时讲解 React 17 的 setState时,setTimeout外是批处理重新渲染一次,setTimeout中是同步渲染,重新渲染两次,能对上。
- 再来看下 React 18 下,render 打印了 2 次,说明组件重新渲染了 2 次,在对比下前面讲解的 React18 的自动批处理功能,setTimeout外部批处理一次,内部批处理一次,重新渲染两次,也能对上.
- 那为什么这期间打印的 count 都是 0 呢?
这是由于js的特性闭包导致的,闭包就是内部函数可以访问外部函数的变量。
组件App是一个函数,handle 是 App内的函数,这也就形成了一个闭包,所以 handle 函数才能访问到 count 变量的值。
无论延时多长时间,最终打印的count值一直是旧值,也就是 0。
要是想要立即用更新后的state,可以使用setState的第二个函数。
相关文章:
react17+18 中 setState是同步还是异步更新
在类组件中使用setState,在函数式组件中使用hooks的useState。 setstate目录 1. 类组件1.1 react 17版本1.2 react 18版本 2、函数式组件 1. 类组件 1.1 react 17版本 参考内容:第十一篇:setState 到底是同步的,还是异步的&…...
Unity框架,ET框架8.1版本的打包流程记录
目录 打包代码前置1.必须要安装Visusal Studio 2022的组件,如下图,必须都要进行安装,不然会在代码重构的时候报错,丢失SDK。Rider的版本必须2023及以上 步骤一、使用Rider编辑器打开项目后进行重构项目步骤二、使用HybirdCLR生成A…...
windows访问wsl中的docker
1、启动windows路由转发功能: 找到任务管理器 --》服务–》打开服务–》 ROUTing and Remote Access 2、关闭wsl中linux的防火墙 3、查看docker系统和linux系统的ip和网关 以下面为例 # docker系统 eth0: flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu…...
golang主要优缺点
优点 1)采用协程机制,可以很方便的支持高并发,性能还不错。 2)非常易于使用,产出效率很高。 缺点 也是协程机制。程序中一切皆协程,并且自己做了协程调度机制,而不是传统的 线程机制。导致需…...
浅谈Redis和一些指令
浅浅谈一谈Redis的客户端 Redis客户端 Redis也是一个客户端/服务端结构的程序。 MySQL也是一个客户端/服务端结构的程序。 Redis的客户端也有多种形态 1.自带命令行客户端 redis-cli 2.图形化界面的客户端(桌面程序,web程序) 像这样的图形…...
AI大模型探索之路-应用篇1:Langchain框架概述—快速构建大模型应用
目录 一、什么是LangChain? 二、LangChain解决了哪些问题? 三、LangChain总体架构 四、代码实践样例 总结 一、什么是LangChain? 为大模型应用提供简便之道。 LangChain,专为构建庞大的语言模型应用程序设计的框架࿰…...
Google Chrome 常用设置
Google Chrome 常用设置 References 转至网页顶部 快捷键:Home 转至内容设置 chrome://settings/content 清除浏览数据 历史记录 -> 清除浏览数据 关于 Chrome 设置 -> 关于 Chrome chrome://settings/help References [1] Yongqiang Cheng, https:/…...
如何提高旋转花键运行稳定性?
现代化精密仪器设备中,精密仪器的稳定工作性能对于生产效率和产品质量至关重要,运行效率和精度是常见问题。旋转花键作为机械传动系统中的重要组成部分,其稳定性也是直接影响到机械装配的质量和使用寿命,那么我们应该如何提升旋转…...
每日一题 第八十七期 洛谷 [蓝桥杯 2018 省 AB] 全球变暖
[蓝桥杯 2018 省 AB] 全球变暖 题目描述 你有一张某海域 N N N \times N NN 像素的照片,. 表示海洋、 # 表示陆地,如下所示: ....... .##.... .##.... ....##. ..####. ...###. .......其中 “上下左右” 四个方向上连在一起的一片陆地组…...
AI技术创业有哪些机会?
文章目录 ✍探索AI技术创业的机会与挑战💎引言💎AI技术的快速发展与应用💎🌹AI技术创业的机会与方向🌹1. 行业解决方案🌹2. 智能产品和服务🌹3. 教育和培训 💎AI技术创业的挑战与应对…...
TensorFlow学习之:基础概念和操作
TensorFlow简介 TensorFlow是一个开源的深度学习框架,由Google的研究团队Google Brain Team开发,并在2015年发布。它是基于DistBelief,Google之前的一个深度学习项目,但被重新设计以便更灵活、更强大、更适应于研究和生产。 历史…...
最新在线工具箱网站系统源码
内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 系统内置高达72种站长工具、开发工具、娱乐工具等功能。此系统支持本地调用API,同时还自带免费API接口, 是一个多功能性工具程序,支持后台管理、上…...
c# InvokeRequested delegate解决线程访问界面
说明 界面操作的代码应该写在界面(Form/Dialog)里 方法定义 private void Method1(string s) {...... }delegate定义 private delegate void Method1Delegate(string s);界面调用代码 private void op(){string sText"hello";if (this.In…...
使用 Web Workers 作为setInterval的替代方案
使用 Web Workers 作为setInterval的替代方案 在 Vue 项目中,为了避免 setInterval 在标签页非激活状态下的不准确问题,我们可以使用 Web Workers 作为一个替代方案 Web Worker 介绍: Web Workers : 浏览器后台为网页运行的一个小助手&…...
python实现将日期文本化
环境:python3.8.10 需要:有些时候,需要在一段文本的后面,添加上日期,尤其是文本重复的情况下,添加上每天的日期更为重要。 代码实现: import datetimetodaydatetime.date.today() date_textto…...
react ant design 通过函数弹出 modal窗口
在React Ant Design中,可以通过调用Modal组件的方法来动态弹出和关闭Modal窗口。具体步骤如下: 1、首先,在组件中引入Modal组件: import { Modal } from antd;2、在组件中定义一个函数来弹出Modal窗口: const showM…...
力扣刷题Days33-209. 长度最小的子数组(js)
目录 1,题目-滑动窗口 2,代码 滑动窗口 3,学习与总结 1,题目-滑动窗口 给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1,…...
面对DDOS攻击,有哪些解决办法
随着互联网带宽的持续增长以及DDOS黑客技术的发展,DDOS拒绝服务攻击的实施变得愈发容易。商业竞争、打击报复、网络敲诈等多种因素,各行各业的用户都曾受到DDOS攻击的威胁。 一旦遭受到DDOS攻击,随之而来的就是业务宕机,用户无法…...
C++ GDAL提取多时相遥感影像中像素随时间变化的数值数组
本文介绍基于C语言GDAL库,批量读取大量栅格遥感影像文件,并生成各像元数值的时间序列数组的方法。 首先,我们来明确一下本文所需实现的需求。现在有一个文件夹,其中包含了很多不同格式的文件,如下图所示。 其中&#x…...
免费-华为od-C卷-javascript-动态规划-贪心歌手.js
动态规划-贪心歌手 还有很多其他题,链接是github, 进去可以查看对应文件夹就行...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
