本文主要分以下两个部分对 Composition API 的原理进行解读:
reactive
API 原理ref
API 原理
reactive
API 原理
打开源码可以找到reactive
的入口,在composition-api/src/reactivity/reactive.ts,我们先从函数入口开始分析reactive
发生了什么事情,通过之前的学习我们知道,reactive
用于创建响应式对象,需要传递一个普通对象作为参数。
export function reactive<T = any>(obj: T): UnwrapRef<T> {
if (process.env.NODE_ENV !== 'production' && !obj) {
warn('"reactive()" is called without provide an "object".');
// @ts-ignore
return;
}
if (!isPlainObject(obj) || isReactive(obj) || isNonReactive(obj) || !Object.isExtensible(obj)) {
return obj as any;
}
// 创建一个响应式对象
const observed = observe(obj);
// 标记一个对象为响应式对象
def(observed, ReactiveIdentifierKey, ReactiveIdentifier);
// 初始化对象的访问控制,便于访问ref属性时自动解包装
setupAccessControl(observed);
return observed as UnwrapRef<T>;
}
首先,在开发环境下,会进行传参检验,如果没有传递对应的obj
参数,开发环境下会给予开发者一个警告,在这种情况,为了不影响生产环境,生产环境下会将警告放过。
函数入口会检查类型,首先调用isPlainObject
检查是否是对象。如果不是对象,将会直接返回该参数,因为非对象类型并不可观察。
然后调用isReactive判断对象是否已经是响应式对象,下面是isReactive
原型:
import {
AccessControlIdentifierKey,
ReactiveIdentifierKey,
NonReactiveIdentifierKey,
RefKey,
} from '../symbols';
// ...
export function isReactive(obj: any): boolean {
return hasOwn(obj, ReactiveIdentifierKey) && obj[ReactiveIdentifierKey] === ReactiveIdentifier;
}
通过上面的代码我们知道,ReactiveIdentifierKey
和ReactiveIdentifier
都是一个Symbol
,打开composition-api/src/symbols.ts
可以看到,ReactiveIdentifierKey
和ReactiveIdentifier
是已经定义好的Symbol
:
import {
hasSymbol } from './utils';
function createSymbol(name: string): string {
return hasSymbol ? (Symbol.for(name) as any) : name;
}
export const WatcherPreFlushQueueKey = createSymbol('vfa.key.preFlushQueue');
export const WatcherPostFlushQueueKey = createSymbol('vfa.key.postFlushQueue');
export const AccessControlIdentifierKey = createSymbol('vfa.key.accessControlIdentifier');
export const ReactiveIdentifierKey = createSymbol('vfa.key.reactiveIdentifier');
export const NonReactiveIdentifierKey = createSymbol('vfa.key.nonReactiveIdentifier');
// must be a string, symbol key i