96SEO 2026-07-25 08:21 1
刚学 React 接触 setState的时候,经常会想一个问题:setState 到底是同步的还是异步的?
“好像是异步的”,结果写代码时又发现有时候它“立刻生效”了。越想越糊涂,直到后来踩了坑、看了源码、再结合 React 的变化。才真正理清楚,

就最近遇到的切换页面主题的react项目,里面的有一下一段代码
const toggleTheme = => {
setTheme;},
这又让我回想起setState这个许久的问题,它和“同步/异步”有关系吗?决定写一篇文章来捋一捋,怎么说呢,
脑子里立刻浮现出那个经典例子:
const = useState;const handleClick = => {
setCount;console.log,、};
这里打印出来的还是老值。导致我一直以为是因为 “setState 是异步的,还没执行完”。老实说,但后来我才意识到——这个理解其实有点跑偏了
为什么 console.log 打印的是?
并不是因为 setCount 像 setTimeout 或者接口请求那样真的是个异步任务,被扔到了微任务队列里。根本原因是 React 为了性能开启了一个叫 “批处理” 的机制。
想象一下你去超市结账。如果你拿一瓶水,收银员算一次钱;再拿包薯片,收银员再算一次钱…,收银员肯定会被你累死。React 很聪明,它会把你的多次 setState 操作先“记在小本本上”。等你这一轮事件处理函数执行完了它再一次性把所有账单结了,这个操作在react里面叫更新dom。其实,
当你执行 console.log 的时候。React 甚至还没开始动手更新呢,你读到的自然是旧值。
为了验证这一点,咱们直接上代码测试。用 React 和 React 对比,真相立马浮出水面。
后来我看了一些老教程,说“在 setTimeout 里 setState 是同步的”。于是我兴奋地去试了一下:
// 环境:React const handleClick = => {
setTimeout => {
setCount;老实说,// 很多人以为这里能打印出 // 结果控制台啪的一下打脸:依然是!,!console.log,},);},
当时我就懵了直到我打开 Chrome 开发者工具的 Elements 面板。盯着那个 DOM 节点看,才发现了一个惊人的事实:
console.log 执行的那一瞬间,页面上的数字已经变成 了。说明 React 确实同步完成了渲染。count 变量没变! 因为我是用函数式组件写的。
这这就触及到了知识盲区: 在 React 的 setTimeout 里React 确实失去了“批处理”的能力,导致它被迫同步更新了视图。,由于函数式组件的闭包特性我当前这个 handleClick 函数是在 `count=` 的时候创建的,它手里拿的 `count` 永远是。
视图是新的,变量是旧的。这才是最坑的地方,
回到 React,官方推出了 **自动批处理**。
setTimeout => {
setCount;setName,setIsLoading;},),
👉 **React 无管你在哪调用状态更新**。都会自动把它们“攒起来”,在当前 tick结束时**一次性合并更新并渲染**。说起来,
这代表着,在 React 里。除非你用 `flushSync`这种逃生舱,否则你几乎看不到 DOM 同步更新的情况了。这其实是好事,心智负担少了很多,不用再去记那些特例。
我们来看最常见的场景。如果它是同步的,那我改三次。
它就应该变三次
// React 环境export default function App { // 组件渲染了!console.log,//埋点:监控渲染次数 const = useState;const handleClick = => { //连发三枪 setCount;setCount,setCount;//马上查看 console.log;},不过,return ;}
**运行结果直接打脸:**
`可以逼 React 同步执行。在 React 里,需要用 `flushSync` 这个 API 来关掉自动批处理。`
import { useState } from 'react';import { flushSync } from 'react-dom';老实说,export default function App { const = useState;const handleClick = => { //第一次更新:强制同步 flushSync => { setCount;}),console.log.innerText);//第二次更新:强制同步 flushSync => { setCount;}),console.log.innerText);},return;}
**结论 :** 看,React 其实完全有能力同步更新。老实说,只要你用 `flushSync`勒令它“立刻 、马上干活”。它就会停下手头的工作,立刻执行更新流程。
准确地说 :setState 本质上是同步执行代码的。只是 React 默认挂了个“防抖”的机制,让它看起来像是异步的。
const handleClick = => {
flushSync => {
setCount;}),//刚才代码证明,DOM 这里已经变成
console.log;},
我们这个 `handleClick` 函数,是在 `count` 为 的那次渲染中生成的。它就像一张照片,永远定格在了那一刻。不论你用办法让 React 在外部把 DOM 更新了,或者把 React 内侧 State 更新了。但你当前正在运行的这个 `handleClick` 函数作用域里,`count` 这个局部变量,它就是个常量 的,再怎么搞它也是 的。
const toggleTheme = => { setTheme;},
为什么要写成 函数形式?
这和“同步/异步”有关系吗?老实说,有关系。不过,
正因为 React 的 setState 是“异步”的。而且函数式组件有闭包陷阱,如果直接写 setTheme,你拿到的 me 很可能是旧值。按理说,
当你传入一个函数时。你是在告诉 React :
麻烦把当时最新的那个状态值传给我的函数。我不信我自己闭包里的旧变量,我只信你传给我的新值。
定性 : “严格来说。setState 是由 React 管理的版本更新,表现得像异步 )。”
亮点 :
补充特例 : “如果需要在 REACT 中强制 同步 更新 DOM。可以使用 flushSync。”
最终补刀: “但无论 DOM 是否 同步 更新,在 函数式组件中,由于 JS 闭包的存在。我们在 当前函数执行上下文中拿到的 state 是本次渲染的快照,要获取 最新值应该依赖 useEffect 或 useRef。”
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback