🔴前端码农,你能讲出 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,可能会引发无限循环
相关推荐
Live&&learn18 小时前
nvm切换node版本时,npm不跟着切换解决
前端·npm·node.js
xixixin_18 小时前
【React】检测元素是否出现在用户视窗内
开发语言·前端·javascript·react.js
谢彦超oooo18 小时前
HTML5 与前端开发要点
前端·html·html5
IT_陈寒19 小时前
Vue 3响应式原理深度拆解:5个90%开发者不知道的Ref与Reactive底层实现差异
前端·人工智能·后端
睡前要喝豆奶粉19 小时前
在.NET Core Web Api中使用JWT并配置UserContext获取用户信息
前端·.netcore
前端加油站19 小时前
一份实用的Vue3技术栈代码评审指南
前端·vue.js
Jonathan Star1 天前
沉浸式雨天海岸:用A-Frame打造WebXR互动场景
前端·javascript
工业甲酰苯胺1 天前
实现 json path 来评估函数式解析器的损耗
java·前端·json
老前端的功夫1 天前
Web应用的永生之术:PWA落地与实践深度指南
java·开发语言·前端·javascript·css·node.js
LilySesy1 天前
ABAP+WHERE字段长度不一致报错解决
java·前端·javascript·bug·sap·abap·alv