Vue3 ref 模块设计拆解

ref 模块的核心目标:

👉 让基本类型也具备响应式能力
👉 提供统一的“值容器抽象”

整体由 4 个核心实现类组成:


1. RefImpl —— 标准 ref

用于 ref / shallowRef

特点:

  • 内部持有 Dep 依赖集合
  • 通过 .value 的 getter/setter 建立响应式
  • 基本类型通过 getter/setter 劫持
  • 对象类型自动转为 reactive

所以 ref 的本质是:

外层 getter/setter + 内层 Proxy

当访问:

  • ref.value → 触发 getter/setter 响应式
  • ref.value.xxx → 触发 Proxy 响应式

setter 内部使用 Object.is 判断变化:

  • 区分 +0 / -0
  • 正确处理 NaN
  • 避免无意义 trigger

这是性能与边界值兼顾的设计。


2. CustomRefImpl —— 自定义 ref

用于 customRef

开发者手动控制:

  • track
  • trigger

适合做:

  • 防抖
  • 节流
  • 缓存
  • 异步数据

本质是开放响应式调度权。


3. ObjectRefImpl —— 对象属性 ref

用于:

toRef(obj, 'key')

设计亮点:

👉 不创建新状态
👉 代理原对象属性

它:

  • 保存原对象引用
  • 读写直接操作原对象
  • 依赖从原对象获取

这保证:

toRef 是“视图”,不是“拷贝”

始终与源对象同步。


4. GetterRefImpl —— getter 函数 ref

用于:

toRef(() => x)

特点:

  • 只读
  • 每次访问执行 getter
  • 依赖由 getter 内部自动收集

它没有自己的 Dep:

依赖来自 getter 访问的响应式数据


工厂函数体系

ref 模块提供一整套转换工具:

ref / shallowRef

创建标准 ref


toRef

把多种类型统一包装成 ref:

  • 已是 ref → 原样返回
  • getter → GetterRefImpl
  • 对象属性 → ObjectRefImpl
  • 普通值 → RefImpl

统一抽象入口。


toRefs

把 reactive 对象拆成多个 ref:

reactive → ref 视图层

注意:

toRefs 不会让普通对象变成响应式

它是拆解工具,不是 reactive 工具。

如果目标不是 reactive:

只是创建包装壳


proxyRefs

为对象创建代理:

  • 访问时自动 unref
  • 赋值时自动写回 ref.value

这是模板自动解包的基础机制。

因为 setup 编译后本质是:

返回一个对象

proxyRefs 负责让模板写法更自然。


工具函数

unref

解包 ref

toValue (3.3+)

组合式函数统一入参:

  • ref → unref
  • function → 执行

减少样板代码。


isRef

通过标记:

__v_isRef === true

判断 ref 类型。


triggerRef

手动触发 ref 更新。

用于 shallowRef 或手动控制场景。