🔴前端码农,你能讲出 React 中 `setState` 原理吗?🤌

🔴 1. setState 是异步的

在 React 中,我们通过 this.state 读取组件状态,通过 this.setState() 更新状态。但是,这个更新过程是"异步"的

为什么异步?

调用 setState() 后,React 不会立即更新 this.state,而是把更新操作放进一个队列,等到"合适时机"统一执行。这就是所谓的 批量更新,目的是提升性能,减少不必要的重复渲染。

例子:

js 复制代码
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 这里打印的还是旧值

哪些情况是异步的?

  • 异步(批量更新)生效:

    • React 生命周期函数中(如 componentDidMount
    • React 合成事件中(如 onClick
  • 同步更新:

    • setTimeoutsetInterval 等原生异步回调中
    • 原生 DOM 事件中

如何获取更新后的值?

可以通过 setState第二个参数 (回调函数)或 componentDidUpdate 钩子获取:

js 复制代码
this.setState({ count: 1 }, () => {
  console.log(this.state.count); // 1
});

componentDidUpdate() {
  console.log(this.state.count);
}

🔴 2. setState 的批量更新机制

React 会在"批处理模式"中,把多个 setState 放入更新队列,最后统一处理,避免重复渲染。

批处理如何触发?

内部有个变量 isBatchingUpdates 控制是否开启批处理:

  • React 生命周期、合成事件中:isBatchingUpdates = true,会批量更新
  • setTimeout、原生事件中:isBatchingUpdates = false,立即更新

更新过程简述:

  1. 调用 setState 时,状态被合并后放入更新队列
  2. 当前组件被标记为"脏组件",放入 dirtyComponents
  3. 等同步代码执行完后,React 再统一调用 render() 更新页面

🔴 3. 为什么不能直接修改 this.state

js 复制代码
this.state.count = 2; // 错误的做法
  • 直接修改不会进入 React 的更新队列,也不会触发组件重新渲染
  • 还可能在后续合并队列时造成 状态丢失

正确做法是永远使用 setState


🔴 4. 批量更新是什么?

  • 本质是 React 的性能优化手段
  • 多次 setState 合并成一次更新,减少渲染次数
  • 类似 Vue 的 nextTick

多次更新的例子:

js 复制代码
this.setState({ a: 1 });
this.setState({ b: 2 });

React 会在下一轮更新中把 { a: 1, b: 2 } 合并起来更新,不会两次单独渲染。


🔴 5. setState 后发生了什么?

大致流程如下:

  1. 合并新状态
  2. 把组件标记为脏(dirty)
  3. 推入更新队列
  4. 在合适时机触发渲染
  5. 进行虚拟 DOM diff,判断哪些需要更新
  6. 最小化真实 DOM 操作

🔴 6. setState 的"陷阱" ------ 循环更新风险

在以下生命周期里 不要调用 setState,否则会引起死循环:

  • shouldComponentUpdate
  • componentWillUpdate

因为这些函数会在每次更新前调用,而你里面又触发了新的 setState,会无限循环。


🔴 7. React 的事务机制

React 通过事务机制(Transaction)控制更新的前后操作:

  • 每次批量更新都封装在一个"事务"中

  • 事务由多个 wrapper 组成,包含:

    • initialize: 更新前操作
    • close: 更新后操作

例如:

js 复制代码
ReactMount._renderNewRootComponent(...) // 会触发事务开始
  • 所有的 setState 都在事务中集中处理
  • 异步操作(如 setTimeout)不在事务中,所以不能批量更新

🔴 8. 总结

  • 永远不要 直接修改 this.state
  • setState异步的,不能立即拿到更新后的值
  • 多次 setState 会被批处理
  • 在异步环境(如 setTimeout)下 setState 是同步的
  • 利用回调或生命周期钩子获取更新后的值
  • 小心在更新钩子中滥用 setState,可能会引发无限循环
相关推荐
szp20051 小时前
为了在浏览器里跑多线程 ONNX 推理,我把自己的支付浮层弄挂了
前端·webassembly
kisshyshy1 小时前
从 useRef 到 Web Worker:理解 React 可变对象与浏览器多线程
前端·javascript·react.js
fatcoder1 小时前
玩转Nginx 04 — 反向代理:给 nginx 接上后端
前端·后端·nginx
Data_Journal2 小时前
什么是 CAPTCHA,它是如何工作的?
java·大数据·服务器·前端·数据库
计算机魔术师2 小时前
我看了这个更新,把原来的检索方案推翻了
前端
zhanghaha13142 小时前
HTML系列教程:3_HTML 基础标签 — 标题、段落、超链接、图像
前端·html
李高钢2 小时前
C# WPF Prism 进阶(二):区域(Region)与模块化(Module)
java·前端·数据库
xyphf_和派孔明3 小时前
Vite 与 Webpack 对比及常见面试题
前端·webpack·vite
明月_清风3 小时前
Pi Agent 深度解析:开源极简终端 AI 编码代理的终极指南
前端·后端·ai编程
fatcoder3 小时前
玩转Nginx 03 — location 匹配规则:让不同的路径各回各家
前端·后端·nginx