Skip to main content

Vue3 源码

响应式系统

Vue 3 的响应式系统主要位于 packages/reactivity 目录下。这个模块负责实现数据的响应式特性,包括 ref、reactive、computed 等。

src/index.ts 是 reactivity 模块的入口文件,导出了主要的响应式 API。

src/reactive.ts,这个文件实现了 reactive 函数,用于将普通对象转换为响应式对象。

packages/reactivity/src/reactive.ts
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) {
return target;
}
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}

function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
if (!isObject(target)) {
if (__DEV__) {
warn(`value cannot be made ${isReadonly ? 'readonly' : 'reactive'}: ${String(target)}`);
}
return target;
}
// target is already a Proxy, return it.
// exception: calling readonly() on a reactive object
if (target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE])) {
return target;
}
// target already has corresponding Proxy
const existingProxy = proxyMap.get(target);
if (existingProxy) {
return existingProxy;
}
// only specific value types can be observed.
const targetType = getTargetType(target);
if (targetType === TargetType.INVALID) {
return target;
}
const proxy = new Proxy(target, targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers);
proxyMap.set(target, proxy);
return proxy;
}

reactive 函数首先判断传入的对象是否为只读对象,如果是,则直接返回该对象。如果不是只读对象,则调用 createReactiveObject 函数,该函数会根据传入的对象类型(普通对象、数组、Map 等)选择不同的代理处理器。

代理处理器包括 baseHandlers 和 collectionHandlers,它们是响应式系统实现的核心。

  • src/baseHandlers 处理对象属性的读写操作,例如 get 和 set 方法
  • src/collectionHandlers 处理集合类的读写操作,例如 Map 和 Set 等

在代理处理器中,通过拦截器机制来实现数据的响应式。例如,在 get 方法中,会调用 track 函数,用于收集依赖关系,在 set 方法中,会调用 trigger 函数,用于触发依赖更新。

  • src/ref.ts:实现了 ref 和 shallowRef
  • src/computed.ts:实现了 computed
  • src/watch.ts:实现了 watch 和 watchEffect
  • src/effect.ts:实现了 effect 函数,用于创建响应式副作用函数,这是依赖收集和触发更新的核心机制
src/ref.ts
export function ref(value?: unknown) {
return createRef(value, false);
}
export function shallowRef(value?: unknown) {
return createRef(value, true);
}

function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue;
}
return new RefImpl(rawValue, shallow);
}

class RefImpl<T = any> {
constructor(value: T, isShallow: boolean) {}

get value() {}

set value(newValue) {}
}