Vue 3 响应式原理 (Reactivity)
Vue 3 使用 Proxy 重构了响应式系统,解决了 Vue 2 中数组监听、属性添加等限制。
1. 核心概念与 Flags
constants.ts 定义了响应式系统中使用的一些核心枚举标志。
typescript
export enum ReactiveFlags {
SKIP = '__v_skip', // 跳过不进行响应式处理
IS_REACTIVE = '__v_isReactive',// 是否是 Reactive 对象
IS_READONLY = '__v_isReadonly',// 是否是 Readonly 对象
IS_SHALLOW = '__v_isShallow', // 是否是浅层响应
RAW = '__v_raw', // 获取原始对象
IS_REF = '__v_isRef', // 是否是 Ref
}
export enum TrackOpTypes {
GET = 'get',
HAS = 'has',
ITERATE = 'iterate',
}2. Ref 实现原理
Ref 用于包装基本类型(也可以是对象),通过 .value 访问。
typescript
class RefImpl<T = any> {
private _rawValue: T
private _value: T
dep: Dep = new Dep() // 依赖收集容器
public readonly [ReactiveFlags.IS_REF] = true
constructor(value: T, isShallow: boolean) {
// 如果不是浅层响应,且是对象,则转换为 reactive 对象
this._rawValue = isShallow ? value : toRaw(value)
this._value = isShallow ? value : toReactive(value)
}
get value() {
this.dep.track() // 收集依赖
return this._value
}
set value(newValue) {
// 检查值是否变化
if (hasChanged(newValue, this._rawValue)) {
this._rawValue = newValue
this._value = toReactive(newValue)
this.dep.trigger() // 触发更新
}
}
}
export function ref(value?: unknown) {
return new RefImpl(value, false)
}3. Reactive 实现原理
reactive 只能用于对象,核心是 Proxy。
typescript
/* reactive.ts (Simplified) */
export function reactive(target: object) {
if (isReadonly(target)) return target;
// 创建响应式对象
return createReactiveObject(target, false, mutableHandlers, reactiveMap);
}
function createReactiveObject(target: object, isReadonly: boolean, baseHandlers: ProxyHandler<any>, proxyMap: WeakMap<any, any>) {
if (!isObject(target)) return target;
// 检查缓存
const existingProxy = proxyMap.get(target);
if (existingProxy) return existingProxy;
// 创建 Proxy
const proxy = new Proxy(target, baseHandlers);
proxyMap.set(target, proxy);
return proxy;
}4. BaseHandlers (Proxy 拦截器)
get 和 set 拦截器是响应式的核心。
typescript
/* baseHandlers.ts (Simplified) */
class BaseReactiveHandler implements ProxyHandler<object> {
constructor(protected readonly _isReadonly = false) {}
get(target: object, key: string | symbol, receiver: object): any {
// 处理 Flags 访问 (isReactive, isReadonly, raw...)
if (key === ReactiveFlags.IS_REACTIVE) return !this._isReadonly;
// 获取结果
const res = Reflect.get(target, key, receiver);
// 收集依赖
if (!this._isReadonly) {
track(target, TrackOpTypes.GET, key);
}
// 递归响应式:如果属性是对象,且不是浅层响应,则继续 reactive 包装
if (isObject(res)) {
return this._isReadonly ? readonly(res) : reactive(res);
}
return res;
}
}5. 依赖收集 (Effect/Dep)
Vue 3 中没有 Watcher 类,而是使用 Effect(副作用)概念。
typescript
/* Dep.ts (Simplified) */
export class Dep {
constructor() {}
track() { /* ... */ }
trigger() { /* ... */ }
}
// 全局依赖映射表:Target -> Key -> Dep
export const targetMap = new WeakMap();
export function track(target: object, type: TrackOpTypes, key: unknown) {
// 核心逻辑:找到当前 target 的 depsMap,再找到 key 对应的 dep,调用 dep.track()
}
export function trigger(target: object, type: TrackOpTypes, key?: unknown) {
// 核心逻辑:从 targetMap 取出 dep,调用 dep.trigger() 执行 effect
}