🔴前端码农,你能讲出 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)
  • 同步更新:

    • setTimeout、setInterval 等原生异步回调中
    • 原生 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,可能会引发无限循环
相关推荐
java1234_小锋1 小时前
【技术专题】HTML5 网页技术 - HTML5 Canvas 基础以及动画入门
前端·html·html5
知了学历孙老师4 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
ShineWinsu6 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说7 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵9 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot9 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot9 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI9 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance9 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端
补码缩写9 小时前
WebCodecs选编码器,探测之后还要验解码和播放
前端