🔴前端码农,你能讲出 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,可能会引发无限循环
相关推荐
打小就很皮...14 分钟前
Tesseract.js OCR 中文识别
前端·react.js·ocr
wuhen_n36 分钟前
JavaScript内存管理与执行上下文
前端·javascript
Hi_kenyon1 小时前
理解vue中的ref
前端·javascript·vue.js
落霞的思绪2 小时前
配置React和React-dom为CDN引入
前端·react.js·前端框架
Hacker_Z&Q2 小时前
CSS 笔记2 (属性)
前端·css·笔记
Anastasiozzzz3 小时前
LeetCode Hot100 295. 数据流的中位数 MedianFinder
java·服务器·前端
Exquisite.3 小时前
Nginx
服务器·前端·nginx
打小就很皮...3 小时前
dnd-kit 实现表格拖拽排序
前端·react.js·表格拖拽·dnd-kit
Ulyanov3 小时前
从静态到沉浸:打造惊艳的Web技术发展历程3D时间轴
前端·javascript·html5·gui开发
打小就很皮...4 小时前
React 19 + Vite 6 + SWC 构建优化实践
前端·react.js·vite·swc