◆
Vue3 源码:ref 实现原理与 RefImpl 解析
Ref 的实现相对比较简单:主要是 RefImpl 这个类,这个类中会有 _rawValue、_value、dep、__v_isRef 四个属性,并且有 get set,当我们创建一个 ref 时便会使用这个类,为什么我们在使用 ref 的时候,总是要 ref.value,就是因为使用 ref.value 我们才能触发 get value 去拿到我们想要的数据。
其中 RefImpl 这个类中的其他四个属性 rawValue、_value、dep、__v_isRef
rawValue是用来保存用户传入的原始的数据值,在用户更新value数据时,我们需要将新的value与之前的原始value进行对比,判断是否要执行更新_value就是用户最终在.value后获取到的值,这个_value是需要经过转换的,因为如果用户传入的原始的值是一个对象,那么我们需要对这个原始的值进行一层reactive包裹,这样才能实现响应式dep:ref同样需要进行依赖收集,dep就是用来保存effect中的activeEffect类的,为的也就是set时执行activeEffect中的run方法__v_isRef: 用来标志当前对象是不是ref对象
import { isObject } from '@vue/shared';
import { trackEffects, triggerEffects, isTracking } from './effect';
import { createDep } from './dep';
import { reactive } from './reactive';
export class RefImpl {
private _rawValue: any;
private _value: any;
public dep;
public __v_isRef = true;
constructor(value) {
this._rawValue = value;
// 看看value 是不是一个对象,如果是一个对象的话
// 那么需要用 reactive 包裹一下
this._value = convert(value);
this.dep = createDep();
}
get value() {
// 收集依赖
trackRefValue(this);
return this._value;
}
set value(newValue) {
// 当新的值不等于老的值的话,
// 那么才需要触发依赖
if (hasChanged(newValue, this._rawValue)) {
// 更新值
this._value = convert(newValue);
this._rawValue = newValue;
// 触发依赖
triggerRefValue(this);
}
}
}
export function ref(value) {
return createRef(value);
}
function convert(value) {
return isObject(value) ? reactive(value) : value;
}
function createRef(value) {
const refImpl = new RefImpl(value);
return refImpl;
}
export function triggerRefValue(ref) {
triggerEffects(ref.dep);
}
export function trackRefValue(ref) {
if (isTracking()) {
trackEffects(ref.dep);
}
}
// 这里没有处理 objectWithRefs 是 reactive 类型的时候
// TODO reactive 里面如果有 ref 类型的 key 的话, 那么也是不需要调用 ref.value 的
// (but 这个逻辑在 reactive 里面没有实现)
export function proxyRefs(objectWithRefs) {
return new Proxy(objectWithRefs, shallowUnwrapHandlers);
}
// 把 ref 里面的值拿到
export function unRef(ref) {
return isRef(ref) ? ref.value : ref;
}
// !!为了转换为 boolean 否则为 undefined
export function isRef(value) {
return !!value.__v_isRef;
}
export function hasChanged(value, oldValue) {
return !Object.is(value, oldValue);
}
模版中为什么不需要使用 .value,因为 vue 在模版中使用了如下这样一个函数
// 这里没有处理 objectWithRefs 是 reactive 类型的时候
// TODO reactive 里面如果有 ref 类型的 key 的话, 那么也是不需要调用 ref.value 的
// (but 这个逻辑在 reactive 里面没有实现)
export function proxyRefs(objectWithRefs) {
return new Proxy(objectWithRefs, shallowUnwrapHandlers);
}
// 这个函数的目的是
// 帮助解构 ref
// 比如在 template 中使用 ref 的时候,直接使用就可以了
// 例如: const count = ref(0) -> 在 template 中使用的话 可以直接 count
// 解决方案就是通过 proxy 来对 ref 做处理
const shallowUnwrapHandlers = {
get(target, key, receiver) {
// 如果里面是一个 ref 类型的话,那么就返回 .value
// 如果不是的话,那么直接返回value 就可以了
return unRef(Reflect.get(target, key, receiver));
},
set(target, key, value, receiver) {
const oldValue = target[key];
if (isRef(oldValue) && !isRef(value)) {
return (target[key].value = value);
} else {
return Reflect.set(target, key, value, receiver);
}
},
};

还没有留言,来发表第一条吧~