问题:setState()到底是同步还是异步?
请看如下场景:

结论:
- 在 >= v18.0.0 时,任何位置调用setState都是异步更新的
- 在 < v18.0.0 时,视调用位置的不同分两种情况:
1、所有在React自身的调度流程中调用时都是异步的,比如生命周期(componentDidMount\componentDidUpdate...)、合成事件(onClick\onMouseEnter...)等
2、在JS原生事件、异步事件、DOM元素绑定的原生事件等都是同步更新的(比如:setTimeout、setInterval、async\await等等)
源码分析
首先,我们来看低于V18.0.0版本以下的。
1、调用setState()后会依次经历以下函数过程:
setState > enqueueSetState > scheduleUpdateOnFiber > flushSyncCallbackQueue
2、flushSyncCallbackQueue是具体执行同步更新的函数,控制是否调用同步的逻辑在scheduleUpdateOnFiber中,所以我们来重点看下scheduleUpdateOnFiber内部的逻辑

从上图圈出的重点内容可以看出,控制是否同步更新的是executionContext变量,那么executionContext变量是什么?何时为NoContent?
executionContext是一个全局变量,标识当前React 执行的阶段。当executionContext值为NoContent时,setState即会同步更新state。那么executionContext何时会修改值?搜索全局发现,进入任何一个React自身的调度事件中都会被赋予相应不同的状态。如下几种式例:


executionContext默认值为NoContent, 所以 ,在React自身调度流程中执行setState是异步更新,其他未进入的则是同步更新。
接下来我们看V18的scheduleUpdateOnFiber函数:

从圈中部分可以看出,要执行同步更新时新增了条件判断,其中一个条件是必须在非concurrent模式下才可进入,react版本不同采用的模式也不同,主要有Legacy、blocking、Concurrent模式。而V18版本以后已经全面采用Concurrent模式,因为功能最全面。所以V18版本以后调用setState都是异步的。 - 但需要理解,setState的异步行为并不是代表setState内代码执行是异步的,其实内部代码是同步的,只不过生命周期和合成事件的执行顺序都在更新之前,所以没法立即拿到修改后的state,需要更新后才能拿到,所以才导致异步效果。目的是为了“批量优化”!
useState中使用setState时有何区别
问题:setState()到底是同步还是异步?
请看如下场景:
结论:
1、所有在React自身的调度流程中调用时都是异步的,比如生命周期(componentDidMount\componentDidUpdate...)、合成事件(onClick\onMouseEnter...)等
2、在JS原生事件、异步事件、DOM元素绑定的原生事件等都是同步更新的(比如:setTimeout、setInterval、async\await等等)
源码分析
首先,我们来看低于V18.0.0版本以下的。
1、调用setState()后会依次经历以下函数过程:
setState > enqueueSetState > scheduleUpdateOnFiber > flushSyncCallbackQueue
2、flushSyncCallbackQueue是具体执行同步更新的函数,控制是否调用同步的逻辑在scheduleUpdateOnFiber中,所以我们来重点看下scheduleUpdateOnFiber内部的逻辑
从上图圈出的重点内容可以看出,控制是否同步更新的是executionContext变量,那么executionContext变量是什么?何时为NoContent?
executionContext是一个全局变量,标识当前React 执行的阶段。当executionContext值为NoContent时,setState即会同步更新state。那么executionContext何时会修改值?搜索全局发现,进入任何一个React自身的调度事件中都会被赋予相应不同的状态。如下几种式例:
executionContext默认值为NoContent, 所以 ,在React自身调度流程中执行setState是异步更新,其他未进入的则是同步更新。
接下来我们看V18的scheduleUpdateOnFiber函数:
从圈中部分可以看出,要执行同步更新时新增了条件判断,其中一个条件是必须在非concurrent模式下才可进入,react版本不同采用的模式也不同,主要有Legacy、blocking、Concurrent模式。而V18版本以后已经全面采用Concurrent模式,因为功能最全面。所以V18版本以后调用setState都是异步的。 - 但需要理解,setState的异步行为并不是代表setState内代码执行是异步的,其实内部代码是同步的,只不过生命周期和合成事件的执行顺序都在更新之前,所以没法立即拿到修改后的state,需要更新后才能拿到,所以才导致异步效果。目的是为了“批量优化”!
useState中使用setState时有何区别