useEffect依赖更新时,其清理函数是否会同步在对应effect函数前执行?
useEffect同步清理函数的执行顺序保证
针对你的问题,在清理函数本身为同步函数的前提下,React官方明确保证:旧effect的清理函数一定会在对应新effect回调执行前被同步调用,该执行顺序是固定可预期的,不存在异步插队的可能。
固定执行流程
对于绑定了相同依赖项的同一个useEffect,其更新触发的完整流程是严格固定的:
- 依赖项发生变化触发组件重渲染
- 组件完成渲染、浏览器完成DOM绘制后,React开始处理effect队列
- 第一步:同步执行上一次渲染生成的该effect对应的清理函数
- 第二步:同步执行本次渲染生成的新effect回调
- 首次渲染时不存在上一次的effect实例,因此不会执行清理逻辑,直接运行effect回调
常见误区说明
很多开发者会因为useEffect「不阻塞渲染」的特性误以为它的内部逻辑是异步打散的,实际上:
- useEffect的调度时机是异步的:React会等浏览器绘制完成后再处理effect,避免阻塞UI更新
- 但effect队列的执行过程是同步的:一旦React开始执行effect队列,会一口气完成所有旧effect清理→新effect执行的流程,中间不会插入任何其他宏任务、微任务,也就不会出现清理和新effect执行顺序错乱的情况
示例验证
你给出的示例代码的打印顺序是完全可复现的:
export default function App() { const [count, setCount] = useState(0); console.log("App: render"); useEffect(() => { console.log("effect"); return () => console.log("cleanup"); }, [count]); return ( <> <h2>useEffect</h2> <button onClick={() => setCount(count + 1)}>Increment</button> </> ); }
每次点击Increment按钮触发count更新后,打印顺序必然为:
- App: render
- cleanup
- effect
不存在任何例外情况。
卸载场景补充
组件卸载时,React同样会同步执行所有未清理的effect的清理函数,这个过程也是批量同步执行的,不会涉及异步逻辑。
内容的提问来源于stack exchange,提问作者Andru
相关产品推荐
相关产品推荐

