vue中props更新不直接重绘子组件,而是通过响应式联动、vnode精确比对和条件复用实现:父数据变→子props被proxy拦截→触发render→生成新vnode→issamevnodetype校验type与key→一致才调用updatechildcomponent逐key校验同步→setter触发子组件重新render。

Vue 组件中 props 更新触发 patch,不是简单地“重绘子组件”,而是通过响应式联动 + 精确比对 + 条件复用完成的。核心在于:父组件数据变 → 子组件 props 被 proxy 拦截 → 触发子组件 render 副作用 → 生成新 VNode → 进入 patch 流程,但是否真正更新 DOM,取决于新旧 VNode 是否被判定为“可复用节点”。
props 更新如何被子组件感知
子组件 props 是响应式的,但它的响应性不来自自身定义,而来自父组件的数据源和 Vue 的依赖追踪机制:
- 父组件修改响应式 prop(如
ref或 reactive 对象属性),Proxy set 拦截触发依赖通知 - 子组件在
setup()或render()中访问该 prop 时,已将其 key(如age)收集进对应的Dep - 当父组件赋值
person.age = 18,若person已是 reactive 对象,则其内部age的 setter 也会触发 notify,子组件 render watcher 重新执行 - 非响应式字段(如直接给对象新增属性)不会触发,必须用
reactive初始化或defineProps显式声明类型
patch 如何判断是否需要更新子组件
进入 patch 阶段后,Vue 不会无条件刷新子组件,而是先调用 isSameVNodeType(Vue 3)或 sameVnode(Vue 2)做“可复用性校验”:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 关键比对项:
type(组件构造器是否相同)、key(存在且一致才可能复用) - 若 type 不同(比如从
Foo切换为Bar),直接卸载旧组件、挂载新组件 - 若 type 相同但 key 变化(如列表中 key 动态生成),则视为不同节点,放弃复用,重建实例
- type 和 key 都一致,才进入
patchComponent,进一步调用updateChildComponent
updateChildComponent:props 的实际更新逻辑
该函数是 props 更新的核心执行入口,它不盲目覆盖,而是逐 key 校验与同步:
- 遍历
_propKeys(初始化时缓存的合法 props key 列表),跳过父组件传入但子组件未声明的字段 - 对每个 key 执行校验:类型检查(如 number 类型传了 string)、默认值回退、required 判断
- 校验通过后,将新值赋给
instance.props[key];由于该属性已被 proxy 包裹,赋值即触发 setter - setter 内部调用
trigger,通知子组件的 render effect 重新运行,生成新 VNode —— 此时才真正进入子组件自身的 patch 流程
避免无效 patch 的关键实践
很多性能问题源于 props 更新未变却反复 patch。关键控制点在“源头”和“粒度”:
- 大型对象 props 透传时,用
shallowRef或markRaw避免不必要的响应式包裹 - 子组件接收对象型 props 后,如无需监听深层变化,用
watch(props, cb, { deep: false })控制响应范围 - 列表渲染务必使用稳定唯一 key(如
:key="item.id"),禁用:key="index" - 计算属性或派生状态中,若返回值确定且不变,可通过缓存或
computed内部短路减少副作用触发
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










