Vue3解析学习 - reactivity 模块

3 阅读2分钟

Vue3 的响应式模块本质是一个:

参数化的 Proxy 工厂系统

核心目标只有两件事:

  1. 分类处理不同类型目标对象

  2. 保证代理实例的唯一性与可复用

整个系统围绕一个核心函数展开:

createReactiveObject

所有响应式 API 都只是它的参数组合。


一、整体架构

reactivity 的核心结构:

工厂函数 → createReactiveObject → Proxy → 全局缓存

特点:

  • 全局统一拦截策略

  • 分类 handler 体系

  • WeakMap 缓存代理实例

  • 防止 Proxy 嵌套

  • 原始对象可追溯

可以理解为:

一个可配置的 Proxy 生成引擎


二、四大工厂函数

Vue 提供 4 个顶层 API,本质是参数不同:

1. reactive —— 深度响应式

reactive(target)

使用:

  • mutableHandlers

  • mutableCollectionHandlers

  • reactiveMap

递归代理所有嵌套对象。


2. shallowReactive —— 浅响应式

shallowReactive(target)

只代理第一层属性:

  • shallowReactiveHandlers

  • shallowCollectionHandlers

  • shallowReactiveMap

适合大对象性能优化。


3. readonly —— 深度只读

readonly(target)

创建不可变视图:

  • readonlyHandlers

  • readonlyCollectionHandlers

  • readonlyMap

仍然追踪依赖,但禁止写入。


4. shallowReadonly —— 浅只读

shallowReadonly(target)

只读 + 浅代理组合。


三、核心函数:createReactiveObject

签名:

createReactiveObject(
  target,
  isReadonly,
  baseHandlers,
  collectionHandlers,
  proxyMap
)

这是 Vue3 响应式的真正入口。

它解决 4 个关键问题:


1. 目标对象分类

Vue 把对象分为两大类:

普通对象类

  • Object

  • Array

集合类

  • Map

  • Set

  • WeakMap

  • WeakSet

集合类型需要特殊 handler,因为它们不是属性访问模型,而是方法驱动模型。


2. Handler 分类体系

结合三个维度:

  • 深 / 浅

  • 只读 / 可变

  • 对象 / 集合

一共形成 8 类拦截器:

Object / Array

  1. mutableHandlers

  2. readonlyHandlers

  3. shallowReactiveHandlers

  4. shallowReadonlyHandlers

Collection

  1. mutableCollectionHandlers

  2. readonlyCollectionHandlers

  3. shallowCollectionHandlers

  4. shallowReadonlyCollectionHandlers

这是其中拦截处理是关键,后面再更。


3. 代理缓存机制

Vue 为每种模式维护一个 WeakMap:

reactiveMap
shallowReactiveMap
readonlyMap
shallowReadonlyMap

规则:

一个原始对象只对应一个 Proxy

流程:

  1. 创建前先查缓存

  2. 命中直接返回

  3. 未命中才创建新 Proxy

好处:

  • 避免重复代理

  • 保持引用一致性

  • 节省内存


4. 防止 Proxy 嵌套

Vue 通过内部标志位控制:

ReactiveFlags.RAW
ReactiveFlags.IS_REACTIVE
ReactiveFlags.IS_READONLY

关键机制:

target[RAW] → 永远指向原始对象

所以:

reactive(reactive(obj))

仍然返回同一个 Proxy。

但允许:

readonly(reactive(obj))

创建只读副本。

这是刻意设计的“对称性规则”。


四、工具函数体系

这些函数是对响应式状态的 introspection(内省能力)。


isReactive

判断是否响应式对象:

  • 如果是 readonly
    → 判断原始对象

  • 否则直接读标志位


isReadonly

读取:

ReactiveFlags.IS_READONLY

isShallow

读取:

ReactiveFlags.IS_SHALLOW

isProxy

判断是否是 Vue 代理对象:

ReactiveFlags.RAW in target

toRaw

递归取出原始对象:

proxy → raw → raw → raw

直到不是 Proxy。


markRaw

跳过代理:

target[SKIP] = true

createReactiveObject 会直接忽略它。

用于:

  • 第三方库实例

  • DOM 对象

  • 性能敏感数据


toReactive / toReadonly

语义化封装:

toReactive(x) → reactive(x)
toReadonly(x) → readonly(x)

主要用于内部统一流程。