参考文章:
react官方解释:setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState()a potential pitfall.
setState的调用到底发生了什么,在调用setState时,react的表现得真的全都是异步的吗?
setState方法调用
在调用此方法后,react会将改变的状态放进一个队列中(pending队列),之后调用enqueueUpdate方法判断是否处于批量处理更新模式,如果判断是正确的那么就将组件保存到dirtyComponents中。enqueueUpdate方法判断不是批量更新模式,那么直接就更新state状态。
[站外图片上传中...(image-7a43f6-1516868303926)]
可以看到这其中有一个关键就是enqueueUpdate函数的判断,如果判断不是批量更新模式那么setState就是立即更新state的值。
this.setState({val: this.state.val + 1})
console.log(this.state.val) // 第一次输出
this.setState({val: this.state.val + 1})
console.log(this.state.val) // 第二次输出
setTimeout(() => {
this.setState({val: this.state.val + 1})
console.log(this.state.val) // 第三次输出
this.setState({val: this.state.val + 1})
console.log(this.state.val) // 第四次输出
})
这四个输出的console分别是 0、0、2、3
可以看到前两次setState并没有直接改变state的值,而timeOut里面的setState就同步的改变了state的值。所以,直接说setState是异步更新是不严谨的。
由 React 控制的事件处理过程 setState 不会同步更新 this.state!
在 React 控制之外的情况, setState 会同步更新 this.state!
也就是说在react内部自定义事件绑定的事件函数,是异步更新,而用addEventListener或setTimeout非react内部绑定事件函数就是同步更新。
函数式setState
顾名思义,也就是setState的参数不再是一个对象,而是一个函数,这样就可以保障setState安全进行批次处理,setState的值就不会出现覆盖现象。
function incre() {
return {score: this.state.score + 1}
}
function handleState() {
this.setState( incre )
this.setState( incre )
this.setState( incre )
}
函数式setState能够保证,每一次调用incre函数时,之前队列中的state修改结果都已经完成。
而函数式setState也并不是完美的,
function incrementMultiple() {
this.setState(increment);
this.setState(increment);
this.setState({count: this.state.count + 1});
this.setState(increment);
}
最后的结果count只增加了2,而不是4,因为遇到了传统的setState方式,所以会把之前的函数时setState的修改效果清空。
网友评论