上一篇我们说到了setState的合并策略,而setState是同步还是异步的,和setState()的批量处理有很大的关系。 可以先看看这个文章在来看同步还是异步的! react中setState()的执行策略是什么?如何合并的那?如何控制合并?
setState()是同步还是异步那?
看看一下代码的执行情况:
import React, { Component } from 'react';
class com2 extends Component {
state = {
num: 0
}
add = () => {
this.setState({
num: this.state.num + 1
})
console.log(this.state.num)
this.setState({
num: this.state.num + 10
})
console.log(this.state.num)
}
render() {
return (
<div>
<button onClick={this.add}>按钮{this.state.num}</button>
</div>
);
}
}
export default com2;
代码执行结果为: react是facebook出版的,想到了很多的优化方案,这就涉及到了 $\color{red}{react内部为了优化setState()的批处理}$,会对setState进行合并,并且相同属性的设置只保留最后一次的设置。,所以this.state.num 会是一个10
但是为什么打印了二次0?这是为什么?
在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到一个updateQueue中延时更新,而isBatchingUpdates默认是false,表示setState会同步更新this.state;但是,有一个函数batcheUpdates,该函数会把isBacthinUpdate修改为true,而当React在调用事件处理函数之前就会先调用这个batchedUpdates将isBatchingUpdates修改为true,这样由React控制的事件处理过程setState不会同步更新this.state,而是异步了!
控制setState的同步还是异步
上面我们得知setState的同步还是异步走的是react的内部合并逻辑,那<font color=red>只要我们绕过react内部的合并逻辑,不让它进入到updateQueue中不就变成同步的了吗?</font> 因为setState()本身就是同步的
利用setTimeout绕过react内部的合并逻辑
import React, { Component } from 'react';
class com2 extends Component {
state = {
num: 0
}
add = () => {
//利用setTimeout绕过react的控制,不让setState()走合并逻辑
setTimeout(() => {
this.setState({
num: this.state.num + 1
})
console.log(this.state.num)
this.setState({
num: this.state.num + 2
})
console.log(this.state.num)
this.setState({
num: this.state.num + 3
})
console.log(this.state.num)
});
}
render() {
return (
<div>
<button onClick={this.add}>按钮{this.state.num}</button>
</div>
);
}
}
export default com2;
总结
异步的情况:
由React控制的事件处理函数,以及生命周期函数调用setState时表现为异步。大部分开发中用到的都是React封装的事件,比如onChange、onClick、onTouchMove等(合成事件中),这些事件处理函数中的setState都是异步的!
同步的情况:
React控制之外的事件中调用setState是同步更新的。比如原生js绑定的事件,setTimeout/setInterval,ajax,promise.then内等 React 无法掌控的 APIs情况下,setState是同步更新state的