ref和reactive
# 概述
ref
和reactive
是工作中最常用到的定义响应式数据的方法, 二者的核心是基于Proxy
处理的。代码参考于 vue3 源码@vue/reactivity
# ref
ref
是基于RefImpl
类实现的,如下所示,每一个ref
包装过返回的对象都会有两个属性:__v_isShallow
和__v_isRef
。由shallowRef
包装的对象__v_isShallow
的值为true
,ref
定义的为false
;_v_isRef
是ref
对象的标志位,表示这是一个ref
对象。
在RefImpl
类的构造器中,如果是ref
包装的,则还会调用toReactive
方法, 这个方法借助于 vue3 的另一个模块@vue/shared
的方法,用以区分是否为对象,亦如下面所示,如果value
是对象,则会调用reactive
方法,由此可以看出ref(p)
中,如果p
是对象,其本质上还是会调用reactive
方法。
RefImpl
类中定义了get
和set
,当我们获取或者设置ref
对象的.value
时会分别调用对应的方法
get value
:这个里面调用了trackRefValue
方法,主要作用就是依赖收集set value
: 方法中调用了shared
工具库中的方法,通过Object.is
比较新值和原始值是否相等,如果不等,则重新赋值原始值,并调用triggerRefValue
方法,进行消息派发
const toReactive = (value) =>
shared.isObject(value) ? reactive(value) : value; // 利用typeof判断value是否为对象
class RefImpl {
constructor(value, __v_isShallow) {
this.__v_isShallow = __v_isShallow;
this.dep = void 0;
this.__v_isRef = true;
this._rawValue = __v_isShallow ? value : toRaw(value); //原始值
this._value = __v_isShallow ? value : toReactive(value); //值
}
get value() {
trackRefValue(this);
return this._value;
}
set value(newVal) {
const useDirectValue =
this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);
newVal = useDirectValue ? newVal : toRaw(newVal);
if (shared.hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal;
this._value = useDirectValue ? newVal : toReactive(newVal);
triggerRefValue(this, 4);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# reactive
reactive
可以递归地将其属性也响应式。
如下所示,reactive
首先判断参数target
是否只读,如果只读,返回target
;否则调用createReactiveObject
方法,顾名思义,该方法就是创建一个响应式的对象
function reactive(target) {
if (isReadonly(target)) {
return target;
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
);
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# createReactiveObject
方法
其内部逻辑如下,
function createReactiveObject(
target,
isReadonly2,
baseHandlers,
collectionHandlers,
proxyMap
) {
if (!shared.isObject(target)) {
return target;
}
if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) {
return target;
}
const existingProxy = proxyMap.get(target);
if (existingProxy) {
return existingProxy;
}
const targetType = getTargetType(target);
if (targetType === 0 /* INVALID */) {
return target;
}
const proxy = new Proxy(
target,
targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers
);
proxyMap.set(target, proxy);
return proxy;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# shallowReactive
编辑 (opens new window)
上次更新: 2024/07/02, 09:57:01