Setstate到底是同步还是异步

同步!

在React中,如果是由React管理的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state 。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

原因: 在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

注意: setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。

isBatchingUpdates 和 batchedUpdates 主要是为了减少React管理的事件处理中 diff的次数为一次。

setState()不是立刻更新组件。其可能是批处理或推迟更新。这使得在调用setState()后立刻读取this.state的一个潜在陷阱。
就像这样:

incrementCount() {
this.setState({count: this.state.count + 1});
}
handleSomething() {
this.incrementCount();
this.incrementCount();
this.incrementCount();
}
调用了3次incrementCount方法, 期望this.state.count的值是3, 但最后却是1
本质上setState修改state的值是通过浅合并把新的值合并到state的对象上,如果多次修改,react会进行批次处理
类似于:

Object.assign(
previousState,
{count: state.count + 1},
{count: state.count + 1},
{count: state.count + 1},
)
之后的调用在同一周期中将会重写之前调用的值,因此数量仅会被加一。若之后的状态依赖于之前的状态,
解决这个问题的方式:

componentDidUpdate或一个setState回调(setState(updater, callback))
当中的每个方法都会保证在更新被应用之后触发
updater函数接收到的prevState 和 props保证都是最新的
incrementCount() {
this.setState((state) => {
return {count: state.count + 1}
});
}
handleSomething() {
this.incrementCount();
this.incrementCount();
this.incrementCount();
}
setState什么时候会异步更新
setState的执行流程:

this.setState(newState)
==>
newState存入pending队列
==>
判断是否处于batch update
==>
如果是的话就保存组件月dirtyComponents中,
如果不是的话就遍历所有的dirtyComponents,调用updateComponent,更新pending state or props
在 React 的 setState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中回头再说,
而 isBatchingUpdates 默认是 false,也就表示 setState 会同步更新 this.state,
但是,有一个函数 batchedUpdates,这个函数会把 isBatchingUpdates 修改为 true,
而当 React 在调用事件处理函数之前就会调用这个 batchedUpdates,造成的后果,就是由 React 控制的事件处理过程 setState 不会同步更新 this.state。

setState会导致re-rederning, 而re-rederning的代价是昂贵的, 所以他们会尽可能的把多次操作合并成一次提交。
因为当传入的是一个函数时,state读取的是pending队列中state的值
setState什么时候会异步更新, 什么时候会同步更新
React是根据isBatchingUpdates来合并更新的, 那么当调用setState的方法或者函数不是由React控制的话, setState自然就是同步更新了。

如componentDidMount等生命周期以及React的事件即为异步更新,这里不显示具体代码。
如自定义的浏览器事件,setTimeout,setInterval等脱离React控制的方法, 即为同步更新

你可能感兴趣的:(Setstate到底是同步还是异步)