React中setState为何在特定场景下呈现同步行为?
React中setState同步/异步表现差异的原因解释
问题场景
以下React类组件代码中,点击按钮的两种执行逻辑,导致setState的表现截然不同:
import React from "react"; class App extends React.Component { state = { data: "start value" }; do = () => { console.log("before setState: " + this.state.data); this.setState({ data: "new value" }); console.log("after setState: " + this.state.data); }; asyncro = async () => { let promise = new Promise((resolve) => { setTimeout(resolve, 1000); }); return promise; }; render() { return ( <div className="App"> <button onClick={async () => { await this.asyncro(); this.do(); }} > click </button> </div> ); } } export default App;
两种执行结果
- 保留
await时的控制台输出:
before setState: start value after setState: new value
- 删除
await后的控制台输出:
before setState: start value after setState: start value
原因解释
核心逻辑:React的批量更新策略
React为了减少不必要的DOM渲染、提升性能,会对特定场景下的setState进行批量更新处理,关键看setState的调用时机:
无await的情况:
do方法直接在React合成事件(onClick)的回调中执行。此时React会把setState的更新请求加入队列,不会立即修改state,而是等当前合成事件的所有代码执行完毕后,再统一批量更新state。所以在setState之后立即打印this.state.data,拿到的还是更新前的旧值。有await的情况:
await this.asyncro()会暂停当前合成事件的回调,等待Promise完成。1秒后Promise resolve,do方法是在异步任务的回调中执行的——此时原合成事件的回调已经执行完毕,React的批量更新机制已经退出。这时调用setState,React会直接同步更新state,所以后续打印能立即获取到更新后的新值。
总结:React仅在合成事件、生命周期钩子函数这两类同步执行的代码块中启用批量更新;在异步回调(比如Promise.then、setTimeout回调)中调用setState,会触发同步更新。
内容的提问来源于stack exchange,提问作者wilcus
相关产品推荐
相关产品推荐

