useEffect结合状态更新的执行顺序及状态更新确定性问题
React useEffect 与状态更新的执行顺序问题
给定组件代码
const MyComponent = () => { const [state, setState] = useState(""); useEffect(function a() { // Do stuff setState("Some value"); }, []) useEffect(function b() { // Do stuff }, [state]); // return some fancy JSX }
已知执行顺序
MyComponent挂载,MyComponent()执行并返回JSX。- 执行函数
a,状态变更进入队列。 - 执行函数
b(此时步骤2的状态变更尚未生效,因此state === "")。
问题
若state可能被此处未提及的其他触发器修改,是否能保证函数a中的setState("Some value")在上述步骤3之后的下一次effect b执行前已完成?
换句话说,是否存在某种场景,使得b因state变更被调用,但a中的setState("Some value")尚未完成?
回答
可以绝对保证函数a中的setState("Some value")会在步骤3之后的下一次effect b执行前完成,不存在你担心的场景,原因如下:
Effect的执行顺序与状态更新队列机制
挂载阶段,React会按组件中useEffect的声明顺序同步执行所有满足依赖条件的effect:先执行完effecta的全部同步代码(包括调用setState将更新加入队列),才会执行effectb。React的状态更新处理时机
React会在当前批次的effect全部执行完毕后,才会处理所有pending的状态更新队列。也就是说,effectb执行完成后,React会立即处理effecta中触发的state更新,触发组件重新渲染。其他触发器的执行时机限制
- 如果其他
state修改是同步触发(比如另一个挂载阶段的effect):它会和effecta的更新一起进入队列,在当前effect批次执行完后被统一处理,不会插队到步骤3之后的下一次effect b执行前。 - 如果其他
state修改是异步触发(比如setTimeout、事件回调):这类代码会在浏览器事件循环的后续阶段执行,此时React已经完成了effecta的更新处理、组件重新渲染以及对应的effect b执行,不会干扰这次流程。
- 如果其他
简言之,React的渲染与effect执行是严格按批次处理的,effect a的状态更新一定会在步骤3之后的首次effect b执行前生效。
内容的提问来源于stack exchange,提问作者Yakmiras
相关产品推荐
相关产品推荐

