vue响应式依赖图是运行时动态构建的“谁用了谁”映射表,通过track(读取时收集activeeffect到targetmap)和trigger(修改时精准执行相关effect)实现按需更新,不预建、不追踪未使用数据。

Vue 的响应式依赖图,本质是一张“谁用了谁”的关系网络。它不是静态结构,而是在运行时动态构建、按需更新的映射表——数据变化时,Vue 不是盲目刷新整个组件,而是顺着这张图,精准通知所有真正依赖该数据的函数或组件。
依赖图是怎么画出来的?靠 track 和 activeEffect
每次访问响应式数据(比如读取 ref.value 或 reactive.obj.name),都会触发 Proxy 的 get 拦截器,内部调用 track() 函数。此时关键角色登场:
- activeEffect:一个全局变量,指向当前正在执行的副作用函数(如组件渲染函数、watch 回调、computed 的 getter)
- targetMap:一个嵌套 WeakMap,结构类似 { target → { key → Set[effect1, effect2] } }
track 就是把 activeEffect 加入对应 (target, key) 的 effect 集合中。这个过程发生在首次渲染、计算属性求值、watch 初始化等读取阶段,不是声明时就建好,而是“用到才记”。
依赖图怎么被使用?靠 trigger 触发精准更新
当数据被修改(set 拦截器触发),Vue 调用 trigger(),它会:
- 从 targetMap 中查出该 (target, key) 对应的所有 effect
- 逐个执行这些 effect(例如重新运行组件的 render 函数)
- 如果 effect 是 computed,还会标记其 dirty 状态,下次读取时才重新计算
注意:数组索引赋值(arr[0] = x)、新增属性(obj.newKey = y)在 Vue 3 中也能被 Proxy 捕获并正确触发对应依赖,这是 Vue 2 无法做到的。
依赖图不是全量记录,而是按需最小化
Vue 不会为每个属性预建依赖列表,也不追踪未被读取的数据。比如模板里只用了 user.name,那 user.email 就不会出现在任何依赖集合中。再比如:
- 同一个 ref 可能在多个组件中被读取 → 它的依赖集合里会有多个渲染 effect
- 一个 reactive 对象的深层属性(state.profile.avatar.url)被访问 → 依赖会落在 url 这一层,而不是整个 state 对象
- 使用 shallowRef 或 shallowReactive → 依赖图只建立在第一层,深层变更不触发更新
你可以这样验证依赖图的存在
在开发模式下,打开浏览器控制台,给响应式对象添加一个属性(如 obj.debug = true),然后执行 console.log(obj)。展开对象,能看到 __v_raw 和 __v_isReactive 等隐藏字段;更进一步,用 effect 手动创建副作用并观察其执行时机,就能直观看到依赖收集与触发的闭环。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










