Ref
源码分析
ref
的本质是基于类的属性访问器
实现的,可以将一个基本类型值
进行包装
craeteRef
将普通类型
变成一个对象类型
ref
值也可以是对象,但是一般情况下是对象直接使用reactive
更合理
RefImpl 类
- beta版本之前版本ref是个对象,由于对象不方便拓展,所以改成了类
- 如果传递
shallow = true
则只是代理最外层
get value 属性访问器
track
收集依赖- 代理
value
会帮我们代理到_value
上
set value 属性设置器
- 判断
新值
和老值
是否改变,改变就更新值 trigger
触发依赖执行
import { hasChanged, isObject } from "@vue/shared";
import { track, trigger } from "./effect";
import { TrackOpTypes, TriggerOpTypes } from "./operations";
import { reactive } from "./reactive";
export function ref(value) { // value 是一个基本数据类型
// 将 普通类型 变成一个 对象类型
return createRef(value);
}
export function shallowRef(value) { // shallowRef Api
return createRef(value, true);
}
function createRef(rawValue, shallow = false) {
return new RefImpl(rawValue, shallow)
}
const convert = (val) => isObject(val) ? reactive(val) : val; // 递归响应式
class RefImpl {
private _value;
public readonly __v_isRef = true; // 产生的实例会被添加 __v_isRef 表示是一个 ref 属性
constructor(private _rawValue, public readonly _shallow) {
// 如果是深度,需要把里面的都变成响应式的
this._value = _shallow ? _rawValue : convert(_rawValue)
}
类的属性访问器
get value() { // 代理 去value 会帮我们代理到 _value 上
track(this, TrackOpTypes.GET, 'value');
return this._value;
}
set value(newVal) {
if (hasChanged(newVal, this._rawValue)) { // 判断新老值是否有变化
this._rawValue = newVal; // 保存值
this._value = this._shallow ? newVal : convert(newVal);
trigger(this, TriggerOpTypes.SET, 'value', newVal);
}
}
}
以上为删减版~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class RefImpl<T> {
private _value: T
public readonly __v_isRef = true
constructor(private _rawValue: T, private readonly _shallow = false) {
this._value = _shallow ? _rawValue : convert(_rawValue)
}
}
get value() {
track(toRaw(this), TrackOpTypes.GET, 'value')
return this._value
}
set value(newVal) {
if (hasChanged(toRaw(newVal), this._rawValue)) {
this._rawValue = newVal
this._value = this._shallow ? newVal : convert(newVal)
trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
}
}
可以看见RefImpl class传递了一个泛型类型T,里头具体包含:
-
有个私有属性_value,类型为T,有个公开只读属性__v_isRef值为true
-
有两个方法,get value(){}和set value(){},分别对应私有属性的读写操作,用于供外界操作value
-
有个构造函数constructor,用于构造对象。构造函数接受两个参数:
- 第一个参数_rawValue,要求是T类型
- 第二个参数_shallow,默认值为true
当通过它构建对象时,会给对象的
_value
属性赋值为_rawValue
或者convert(_rawValue)
再看convert源码如下:
const convert = <T extends unknown>(val: T): T =>
isObject(val) ? reactive(val) : val
通过源码我们发现,最终,Vue会根据传入的数据是不是对象isObject(val),如果是对象本质调用的是reactive,否则返回原始数据
以上文章来源于某度、某知、某金。