vue响应式系统是proxy拦截→依赖收集→异步触发effect的闭环,通过effect建立数据与视图的双向依赖关系,实现精准更新。

Vue 响应式系统不是“监听变化后更新视图”这么简单,而是一个由读取触发收集、修改触发通知、执行时自动关联的闭环。这个闭环从 Proxy 拦截开始,到 effect 重新运行结束,中间每一步都精准对应数据与视图的依赖关系。
Proxy 是响应式的入口关卡
Vue 3 放弃 Object.defineProperty,改用 Proxy 实现响应式,核心原因在于它能真正“代理整个对象”,而不是逐个定义属性。这意味着:
- 新增或删除属性能被直接捕获,无需 $set / $delete
- 数组索引赋值、length 修改、for...in 遍历等操作均可拦截
- get 拦截器中可递归处理嵌套对象,实现深度响应式(遇到非原始值就 reactive() 一层)
- set 拦截器会比对新旧值(使用 Object.is),仅当真实变化时才触发更新
依赖收集(Track)发生在读取时刻
依赖不会在数据创建时就绑定,而是在组件首次渲染、computed 执行或 watch 调用过程中,**实际读取响应式属性时才发生**。关键点包括:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 只有当前有活跃的 effect(比如 setup 中的渲染函数),读取 ref.value 或 reactive 对象属性,才会触发 Track
- 每个响应式属性背后隐含一个 Dep(依赖集合),用于存放所有依赖它的 effect
- effect 与 Dep 双向记录:Dep 记得谁依赖我,effect 也记得自己依赖了哪些 Dep,卸载时可双向清理
- 同一属性在模板中多次出现,只收集一次依赖(Set 去重)
触发更新(Trigger)不是立刻刷新 DOM
当响应式数据被修改,Proxy 的 set 拦截器会调用 trigger,但它不直接更新视图,而是启动一个调度流程:
- 找到该属性对应的 Dep,遍历所有已注册的 effect
- 把 effect 推入一个异步更新队列(nextTick 微任务),避免重复触发
- 队列去重:同一 effect 即使被多个属性触发,也只执行一次
- 等到 DOM 更新前一刻,批量执行所有待更新的 effect,再统一 patch 视图
effect 是连接数据与行为的纽带
无论是组件渲染、watch 监听还是 computed 计算,底层都靠 effect 封装逻辑。它让 Vue 知道:“这段代码依赖哪些数据,数据变了就请重新跑我”。例如:
- setup 中的模板编译结果,本质是包裹在 effect 里的 render 函数
- watch(() => state.count, ...) 创建的也是一个 effect,只是带了回调包装
- computed(() => a + b) 同样返回一个 effect,其返回值被缓存并响应式追踪
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









