一、ref介绍
ref是vue3中的一个响应式api,官方文档中对其描述是:
其接受一个内部值并返回一个响应式且可变的ref对象。ref对象具有指向内部值得单个property
.value。
直白的说,就是ref是一个函数,其可接收一个参数并会返回一个响应式的对象,此响应式对象有一个value属性,value属性的值指向传入的参数,访问和修改value属性等同于修改原始参数,只是ref提供了响应式能力。
二、源码分析
// packages\reactivity\src\ref.ts
// ref函数的定义
export function ref<T extends object>(value: T): ToRef<T>
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
export function ref(value?: unknown) {
return createRef(value)
}
// createRef函数定义
function createRef(rawValue: unknown, shallow = false) {
// 如果传入的值已经是ref类型,直接返回该值,不做处理
if (isRef(rawValue)) {
return rawValue
}
// 实例化一个RefImpl对象,并返回
return new RefImpl(rawValue, shallow)
}
// RefImpl Class定义
class RefImpl<T> {
private _value: T
public readonly __v_isRef = true
// 构造函数,接受2个参数
// 参数1:原始值
// 参数2:是否是shallowRef
constructor(private _rawValue: T, public readonly _shallow: boolean) {
this._value = _shallow ? _rawValue : convert(_rawValue)
}
// value属性的get方法
get value() {
// get时进行了一次track(即:依赖收集)
track(toRaw(this), TrackOpTypes.GET, 'value')
// get时返回的是原始值
return this._value
}
// value属性的set方法
set value(newVal) {
// 判断值是否发生更改,采用!==运算符比较
if (hasChanged(toRaw(newVal), this._rawValue)) {
// 更改原始值
this._rawValue = newVal
this._value = this._shallow ? newVal : convert(newVal)
// 触发trigger(即:更新通知)
trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
}
}
}
三、总结
ref的源码不多,整个调用过程很清晰:ref函数->调用createRef函数->实例化RefImpl并返回;在实例化RefImpl时,通过设置value属性的get和set方法,进行依赖的收集和更新通知,核心在于track和trigger方法如何进行依赖收集和更新通知。