看完了reactive的代码后, 在看来看ref就会发现根本不是一个量级,在看源代码以前,我以为就是把非引用的数据,报一层对象直接调用reactive的,但是却不是这个样子。下面来看一下代码吧;

入口文件

1
2
3
4
5
6
7
/**
* @info 入参就一个数据或者可以不传数据
*/
export function ref(value?: unknown) {
return createRef(value, false)
}

可以看出,只是调用createRef,传入当前值和一个false,这个false是做什么的呢?继续看

createRef

都在代码里了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 老规矩判断有没有内部的标记来判断是不是已经是ref了
export function isRef(r: any): r is Ref {
return !!(r && r.__v_isRef === true)
}
// 刚刚boolean是 shallow,代表是不是只监听最外层数据变化
function createRef(rawValue: unknown, shallow: boolean) {
// 已经是了就直接返回
if (isRef(rawValue)) {
return rawValue
}
// 套娃继续
return new RefImpl(rawValue, shallow)
}

RefImpl

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
29
30
31
32
33
34
35
36
 class RefImpl<T> {
// 当前的值
private _value: T
// 旧的值
private _rawValue: T

// 收集当前数据的依赖
public dep?: Dep = undefined
// 标记数据类型,这里直接挂在实例上了,没通过代理的钩子函数返回
public readonly __v_isRef = true

constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
// 继续套娃,toReactive会监听引用数据类型,对于非引用类型直接返回当前的值
// export const toReactive = <T extends unknown>(value: T): T =>
// isObject(value) ? reactive(value) : 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 (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = useDirectValue ? newVal : toReactive(newVal)
triggerRefValue(this, newVal)
}
}
}

trackRefValue 收集依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export function trackRefValue(ref: RefBase<any>) {
// effect.ts中的的全局变量
if (shouldTrack && activeEffect) {
// 这里解析成原始对象
ref = toRaw(ref)
if (__DEV__) {
// effect.ts中的方法
trackEffects(ref.dep || (ref.dep = createDep()), {
target: ref,
type: TrackOpTypes.GET,
key: 'value'
})
} else {
trackEffects(ref.dep || (ref.dep = createDep()))
}
}
}

triggerRefValue 触发依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

export function triggerRefValue(ref: RefBase<any>, newVal?: any) {
ref = toRaw(ref)
const dep = ref.dep
if (dep) {
if (__DEV__) {
triggerEffects(dep, {
target: ref,
type: TriggerOpTypes.SET,
key: 'value',
newValue: newVal
})
} else {
triggerEffects(dep)
}
}
}

代码看完以后,ref对于普通变量直接通过自身的getset实现数据的变化监听,但是对于引用类型的数据调用toReactive进行变化监听。