⚡ 30 秒速记

  • 核心判断:状态更新是否立刻可见取决于调度边界和批处理,不应简单记成“同步”或“异步”
  • 原理主线:围绕 「从一道面试题说起」、「异步的动机和原理——批量更新的艺术」、「“同步现象”背后的故事:从源码角度看 s」 建立输入、状态变化与输出之间的因果关系
  • 文章范围:解析了 React setState 的同步与异步机制,通过代码示例和原理分析,帮助开发者理解 setState 在不同场景下的执行时机、批量更新机制及其对组件状态管理的影响,是面试和实际开发中常见高频问题的权威解答。
  • 边界与代价:React 18 自动批处理范围扩大,读取旧值、连续更新和强制同步提交需要分别讨论
  • 工程落地:依赖前值时使用函数式更新;只有确有 DOM 读取时才考虑同步提交,并评估阻塞代价

setState 不能简单归类为同步或异步,状态何时可见取决于 React 的批处理边界。 在受 React 管控的事件中,多次更新会先进入队列并合并,避免每次调用都触发一次完整的重渲染,所以紧接着读取往往还是旧值。对象形式连续写入同一字段时,读取的又是同一个旧状态,最终不等于累加多次。原文中 setTimeout 后立即可见属于 React 15 的历史实现现象,不能直接套到其他版本。

这篇文章不要按 API 清单来背。先用上面的 Mind Map 建立全局结构,再通过交互 DEMO 观察正常路径和边界路径如何改变状态;阅读正文时重点核对每一步的输入、负责执行的参与者、产生的中间状态以及最终可观察结果。遇到版本敏感结论,要把“历史实现”“当前行为”和“工程兼容策略”分开说明;遇到性能或架构取舍,则用实际指标、失败现象和验证手段支撑判断。

版本校准: 原理文章中的代码代表特定实现与写作时间。应用到当前项目时,应先确认浏览器、框架或工具的主版本,再区分稳定的规范语义、可变化的内部实现和项目自身约束。

# 从一道面试题说起

这是一道变体繁多的面试题,在 BAT 等一线大厂的面试中考察频率非常高。首先题目会给出一个这样的 App 组件,在它的内部会有如下代码所示的几个不同的 setState 操作:

import React from "react";
import "./styles.css";
export default class App extends React.Component{
  state = {
    count: 0
  }
  increment = () => {
    console.log('increment setState前的count', this.state.count)
    this.setState({
      count: this.state.count + 1
    });
    console.log('increment setState后的count', this.state.count)
  }
  triple = () => {
    console.log('triple setState前的count', this.state.count)
    this.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)
  }
  reduce = () => {
    setTimeout(() => {
      console.log('reduce setState前的count', this.state.count)
      this.setState({
        count: this.state.count - 1
      });
      console.log('reduce setState后的count', this.state.count)
    },0);
  }
  render(){
    return <div>
      <button onClick={this.increment}>点我增加</button>
      <button onClick={this.triple}>点我增加三倍</button>
      <button onClick={this.reduce}>点我减少</button>
    </div>
  }
}
webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部