React 中不存在“Patch 阶段”这一官方生命周期阶段,它只是 Fiber 协调过程中底层 DOM 差分更新的实现细节,不暴露任何钩子;开发者可使用的更新后钩子仅有 componentDidUpdate、useEffect 和 useLayoutEffect。

React 中没有“Patch 阶段”这个官方生命周期阶段。这是对 React 内部机制的常见误解——Patch 并非用户可感知或可干预的生命周期环节,而是 Fiber 协调(reconciliation)过程中底层 DOM 差分更新(diff + patch)的实现细节,完全由 React 自行调度,不暴露任何钩子函数供开发者使用。
为什么不存在 Patch 阶段的钩子?
React 的更新流程分为两个逻辑层:
-
Render 阶段(可中断、纯计算):生成新的 Fiber 树,执行如
render、getDerivedStateFromProps、shouldComponentUpdate等钩子;此阶段不操作真实 DOM,可被高优先级更新(如用户输入)打断。 -
Commit 阶段(不可中断、副作用):将 Render 阶段产出的副作用(如 DOM 插入/更新/删除、
useLayoutEffect、componentDidMount等)一次性同步提交。其中 DOM 的实际修改(即常说的 “patching”)就发生在此阶段末尾,但它是底层渲染器行为,不对应任何生命周期方法。
你真正能响应的“更新后”时机只有 Commit 阶段钩子
如果你希望在 DOM 被真实更新后执行逻辑,应使用以下明确暴露的钩子:
-
componentDidUpdate(类组件):在 commit 完成、DOM 已更新、浏览器可能已重绘之后触发;适合 DOM 测量、第三方库同步、日志上报等。 -
useEffect(函数组件):在浏览器绘制完成后异步执行,适合数据获取、订阅、手动清理等不影响渲染的副作用。 -
useLayoutEffect(函数组件):在 commit 阶段同步执行,DOM 更新后、浏览器绘制前;适合需要读取布局并同步修改 DOM 的场景(如动画起始帧设置)。
注意被废弃或误用的“Patch 相关”说法
有些资料中提到的 “patch 阶段钩子”,往往混淆了以下概念:
- 把
getSnapshotBeforeUpdate误称为“patch 前钩子”:它确实在 DOM mutation 之前调用,但目的是捕获更新前的 DOM 信息(如滚动位置),并非参与 patch 过程本身。 - 将
ReactDOM.flushSync的强制同步行为理解为“进入 patch”:这只是让当前更新跳过并发调度、立即进入 commit,仍不提供额外钩子。 - 用 “patch” 描述
setState后的状态合并:这属于状态管理语义,与 Fiber 的 patch 行为无关。
React 的设计原则是隔离用户逻辑与底层渲染细节。你无需、也不应试图监听或干预 patch 行为——它由 Fiber 调度器全自动、高效、安全地完成。


















