复杂对象 Props 增量更新需避免全量替换,应通过 $set(Vue 2)或 reactive 属性赋值(Vue 3)精准修改字段;深层嵌套须确保路径存在且响应式;严禁直接修改 props,须通过 $emit 通知父组件更新;响应性取决于父组件传递的是否为响应式源。

复杂对象 Props 增量更新的关键,在于不直接替换整个对象,而是精准修改其内部字段,并确保 Vue 能够侦测到变化。直接 this.obj = { ...this.obj, newField: 'val' } 会触发全量响应式重建,丢失原有引用关系、破坏子组件状态、浪费 diff 开销。
用 $set(Vue 2)或 reactive + 属性赋值(Vue 3)
新增顶层属性必须走响应式 API,不能靠点号或中括号直接添加:
- Vue 2:用
this.$set(this.obj, 'status', 'loading')—— 这会触发依赖通知,且不破坏原对象引用 - Vue 3(Options API):若
obj是reactive({})创建的,可直接this.obj.status = 'loading',Proxy 天然支持新增 key 的响应性 - Vue 3(Composition API):同样需确保源对象是
reactive或ref包裹的,obj.value.status = 'done'或obj.status = 'done'(若 obj 是 reactive)均有效
深层嵌套字段更新要“触达到底”
如果要改的是 props.user.profile.avatarUrl,但 profile 初始为 null 或未定义,那后续直接赋值仍不会响应:
- 初始化时尽量提供完整结构:
user: { profile: {} },而非user: { profile: null } - 对可能为空的层级,先用
$set(Vue 2)或nextTick后赋值(Vue 3),或统一用reactive初始化整个树 - 避免
this.obj.user.profile = { avatarUrl: '...' }这类“整层替换”,应逐级设置:this.obj.user.profile.avatarUrl = '...'
禁止直接修改 props 对象
即使技术上能成功添加属性(如 props.data.id = 123),也违背单向数据流原则:
- 父组件不会感知该变更,视图与真实状态脱节
- 开发模式下 Vue 会警告:“Avoid mutating a prop directly”
- 正确做法是子组件
$emit('update:data', { ...props.data, id: 123 }),由父组件决定是否更新源数据 - 配合 v-model 或 .sync 语法糖,可进一步简化父子通信逻辑
区分“响应式源”和“普通传入对象”
Props 是否响应,取决于它从哪来:
- 父组件用
data()或ref/reactive定义的对象,再传给子组件 → 子组件接收到的是响应式代理,可安全增量更新(通过合法方式) - 父组件传的是字面量对象(如
:config="{ theme: 'dark' }")或 JSON.parse() 结果 → 非响应式,子组件无法触发更新,必须由父组件控制变更 - 不确定时,可在子组件
mounted中打印Object.isReactive(props.xxx)(Vue 3)或检查__ob__(Vue 2)验证


















