Vue 3:响应式原理、Proxy、ref 与 reactive
一、总览:从 Vue 2 到 Vue 3
- Vue 2:递归
Object.defineProperty,难以优雅覆盖新增/删除属性、部分数组场景需补丁。 - Vue 3:
Proxy + Reflect,在「读取」路径上做 track,在「写入/删除」路径上做 trigger;配合 effect 作为订阅单元(概念上接替部分 Watcher 职责)。
二、Proxy 基础
js
const proxy = new Proxy(target, handler)- target:被代理对象。
- handler:
get、set、deleteProperty等陷阱函数。
Vue 中 reactive 对普通对象、ref 对原始值包装对象,本质都依赖代理与依赖映射表(WeakMap → Map → Set)。
三、简化版 reactive + effect
文档给出 effect 栈 + targetMap + track/trigger + reactive 迷你实现,演示:
effect(fn)执行时登记当前活跃 effect。get→ track 把 effect 绑定到target[key]。set/deleteProperty→ trigger 重新运行相关 effect。
真实 Vue 还包含:递归代理策略、ref unwrap、readonly、scheduler 队列、数组/集合类型分支等。
四、Reflect 的角色
- 统一默认语义(返回值、
this绑定)。 - 与 Proxy 陷阱协作:
Reflect.get/set等。
五、响应式 API 一览
| API | 用途 |
|---|---|
| ref | 任意类型;原始值包在 { value } 里;模板自动解包 |
| reactive | 仅对象类型(含数组、Map、Set) |
| shallowRef / shallowReactive | 浅层追踪,适合大体量替换场景 |
| readonly | 深度只读代理,避免下游修改 |
| computed | 派生值,带缓存 |
| toRef / toRefs | 解构 reactive 不丢响应式 |
| triggerRef | 手动触发 shallowRef 更新 |
| markRaw / toRaw | 退出响应式体系(性能或与第三方库互操作) |
ref vs reactive
- 类型:ref 通用;reactive 仅限引用类型。
- 访问:setup 内 ref 要
.value,reactive 直接点属性。 - 整体替换:ref 可整体换
.value;reactive 不能整体替换引用(常用 ref 承载异步整块数据)。 - 解构:reactive 直接解构会丢响应式 → toRefs。
shallow 场景
大对象仅需展示、每次接口返回整体替换 → shallowRef 可减少深度代理成本。
六、effect / watch / computed 的关系
- effect:运行函数并自动追踪依赖 —— 渲染、watch 底层都与之相关。
- computed:带缓存的派生;依赖不变不重复计算。
- watch:显式数据源 + 回调,适合异步副作用。
