vue中props更新触发副作用函数依赖“依赖收集+精准触发”闭环:访问props时track收集依赖,父组件修改props时trigger重执行effect;对象props需实际读取路径才响应深层变化,解构或条件访问易导致失效。

Vue.js 处理组件属性(props)更新时引发的副作用函数,核心在于“依赖收集 + 精准触发”闭环,而非简单监听变化。props 本身是只读响应式数据,其更新由父组件驱动,子组件通过 track 收集依赖、trigger 触发 effect 重执行,整个过程自动完成,但行为高度依赖访问路径和响应式结构。
props 更新如何触发副作用函数
当父组件修改传给子组件的 props 值(如 age: 25 → age: 26),子组件中已读取过 props.age 的副作用函数(如 render 函数、watchEffect 或 computed)会被重新执行。这是因为:
- 子组件初始化时,访问
props.age触发 getter,将当前活跃 effect(如组件 render)加入age对应的依赖集合(Dep) - 父组件更新
age时,触发 setter,内部调用trigger(target, 'set', 'age') - 该 trigger 查找
age的 Dep,把其中所有 effect 推入调度队列(如queueJob) - 下一个微任务中批量执行这些 effect,实现 DOM 重渲染或逻辑重计算
对象类型 props 的深层响应性关键点
当 props 是对象(如 person: { name: 'Alice', age: 30 }),子组件是否响应 person.age 变化,取决于它是否在初始化时“真正读取”过该路径:
- 若子组件模板写了
{{ person.age }}或 script 中执行了props.person.age,则person和person.age都被 track,父组件改this.person.age = 31会触发更新 - 若仅访问
props.person而未深入读取.age,则person.age的变化不会触发 effect —— Vue 不预收集未访问的嵌套属性 - 注意:对象引用不变时(如
this.person.age = 31),因person本身仍是同一响应式对象,其内部age的 set 拦截仍生效;但若父组件替换整个对象(this.person = { ... }),则旧依赖失效,需重新 track
常见失效场景与规避方式
props 更新后副作用未执行,多数源于依赖未建立或被绕过:
- 解构丢失响应性:写
const { age } = props后使用age,实际读取的是普通变量,不再触发 track;应改用props.age或toRefs(props) - 条件分支跳过读取:如
props.show && props.message,当show为 false 时message不被 track,后续show变 true 也不会自动补收依赖;可改用watch(() => [props.show, props.message], ...)显式监听 - 使用
shallowRef或markRaw包裹 props 数据,会阻断 proxy 拦截,导致 set 不触发 trigger - 在非 effect 上下文(如生命周期钩子外的普通函数)直接修改 props,违反只读约定,且无法触发响应链
主动控制副作用执行时机
默认情况下,props 更新会同步标记 effect 为待执行,并在微任务中批量刷新。如需自定义行为,可用调度器(scheduler):
- 在
watch或watchEffect中传入{ scheduler: job => setTimeout(job, 100) },延迟执行 - 对频繁更新的 props(如输入框实时值),配合防抖:
scheduler: throttle(job, 300) - 需要清理上一次异步操作时,在 effect 内返回 cleanup 函数,例如中断 pending 的
fetch请求
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










