一聚教程网:一个值得你收藏的教程网站

热门教程

Patch 过程中对组件实例更新逻辑剖析

时间:2026-06-20 10:54:53 编辑:袖梨 来源:一聚教程网

组件实例是否更新由 shouldUpdateComponent 决定:它在父组件 patch 中提前调用,仅当返回 true 才执行子组件 diff 与渲染;默认浅比较 props、children、slots 引用变化;支持自定义逻辑优化更新。

组件实例在 patch 过程中是否更新,不取决于 DOM 差异本身,而由上层调度提前决定——关键在于 shouldUpdateComponent 这个守门函数是否放行。

shouldUpdateComponent 是更新的决策入口

它在父组件 patch 流程中、准备比对子组件 VNode 之前被调用,传入新旧两个 VNode(n1 和 n2)。只有当它返回 true,后续的 diff、re-render、DOM 更新才会执行;返回 false 则直接跳过整个子组件更新流程,包括其子树。

  • 触发前提是:子组件已挂载(n1.component 存在),且 n2.type 是组件类型
  • 不是在 patch 函数内部执行,而是在 processComponent 或 patchComponent 阶段主动调用
  • 它是纯函数,无 this、无副作用,只依赖两个 VNode 参数

默认浅比较的三项内容

Vue 3 默认实现会依次检查以下三类内容是否发生引用变化(=== 或 Object.is):

  • Props:遍历 n1.props 和 n2.props 的每个 key,任一 value 引用不同即返回 true
  • Children:直接比较 n1.children === n2.children,不递归比对内容
  • Slots:比较 n1.slots 与 n2.slots 是否为同一对象引用;注意函数式插槽每次渲染都会生成新函数,极易导致误判为“需更新”

只要其中一项有变,就认为组件需要更新;全部未变才返回 false,跳过 patch。

自定义 shouldUpdateComponent 的典型场景

你可以在 defineComponent 选项中显式声明它,覆盖默认逻辑:

  • 忽略不影响视图的 prop 变化,例如仅用于埋点的 debugIdtrackKey
  • 基于业务状态做条件更新,比如只在 nextVNode.props.status === 'done' 时才允许更新
  • 手动控制插槽稳定性,例如将插槽函数缓存为 ref 或 memoized 函数,避免因引用变化触发冗余更新

注意:该函数不能写在 setup 返回对象中,必须作为组件定义选项传入。

和 React shouldComponentUpdate 的本质区别

尽管名字相似,但二者定位完全不同:

  • React 的 shouldComponentUpdate 是实例方法,可访问 this.propsthis.state,默认返回 true,几乎必须重写才有优化效果
  • Vue 的 shouldUpdateComponent 是无状态纯函数,只接收 VNode,更轻量、更可控,且 Vue 默认已启用浅比较,多数场景无需干预
  • 它天然适配编译时优化(如静态提升、patch flag),是响应式更新链路中更前置、更底层的一道防线

热门栏目