🔴前端码农,你能讲出 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,可能会引发无限循环
相关推荐
开发者小天23 分钟前
为什么 /deep/ 现在不推荐使用?
前端·javascript·node.js
如白驹过隙1 小时前
cloudflare缓存配置
前端·缓存
excel1 小时前
JavaScript 异步编程全解析:Promise、Async/Await 与进阶技巧
前端
Jerry说前后端1 小时前
Android 组件封装实践:从解耦到架构演进
android·前端·架构
步行cgn2 小时前
在 HTML 表单中,name 和 value 属性在 GET 和 POST 请求中的对应关系如下:
前端·hive·html
hrrrrb2 小时前
【Java Web 快速入门】十一、Spring Boot 原理
java·前端·spring boot
找不到工作的菜鸟2 小时前
Three.js三大组件:场景(Scene)、相机(Camera)、渲染器(Renderer)
前端·javascript·html
定栓2 小时前
vue3入门-v-model、ref和reactive讲解
前端·javascript·vue.js
专注API从业者2 小时前
基于 Flink 的淘宝实时数据管道设计:商品详情流式处理与异构存储
大数据·前端·数据库·数据挖掘·flink
龙在天2 小时前
H5开发,开发照相机,以及组件封装
前端