React setState 到底是同步还是异步
相信很多小伙伴们都一直在疑惑,setState 到底是同步还是异步。请往下看。
- 初始化一下 state
this.state = {
num: 0,
};
- 在 componentDidMount 中敲入以下代码
this.setState({
num: this.state.num + 1,
});
console.log(this.state.num);
在重新给 num 进行加一操作后,就立马在下面 console.log 打印以下输出结果,这是很多小伙伴会出现操作。但是输出的结果却是: 0 。这时很多小伙伴就会得出结论 this,setState 是异步,因为先把 this.setState 放入到任务队列中,首先执行了同步的打印输出操作,再去任务队列中执行 this.setState,就这样断定 this.setState 是异步
- 可是接下来继续在 componentDidMount 中执行以下代码
setTimeout((_) => {
this.setState({
num: this.state.num + 1,
});
console.log(this.state.num);
}, 0);
这时输出的结果却是 :2,这就很奇怪,之前不是异步吗,现在放在 setTimeout 定时器中怎么就变成同步了呢?别着急,继续往下看
- 继续在 componentDidMount 中输入代码
window.addEventListener("click", (_) => {
this.setState({
num: this.state.num + 1,
});
console.log(this.state.num);
});
结果:只要点击窗口, num 就加一,然后输出加一后的结果(3、4、5、6.。。。),也是同步。
总结:(以下是个人总结)
其实 setState 同步还是异步,答案是不确定的。在执行 this.setState(newState) 的时候,会把 newState 存入到 pending 队列中, 接着 判断 是否处于 batchUpdate 中,判断的依据是 React 可以管理到的入口(例如生命周期以及生命周期调用的函数、合成事件),这些受 React 控制的,在执行函数前会将 isBatchingUpdates 设置为 true,在处理结束后会将 isBatchingUpdates 设置为 false 。而 setTimeout 以及DOM操作这些原生事件(不受到 React 控制)都会直接去更新 state。从而会出现同步异步不同的现象。以上为个人总结