源码版本:3.2.37
源码相对路径:packages/reactivity/src/ref.ts
参考 Vue3 组合式API,ref 相关函数有:
响应式:工具
- isRef
- unref
- toRef
- toRefs
响应式:核心
- ref
响应式:进阶
- shallowRef
- triggerRef
- customRef
工具API
isRef
该函数判断传入值的属性 __v_isRef 是否为 true
export function isRef(r: any): r is Ref {
return !!(r && r.__v_isRef === true)
}
unref
该函数判断传入值是 ref对象 的情况下,返回 ref.value,否则返回传入值
export function unref<T>(ref: T | Ref<T>): T {
return isRef(ref) ? (ref.value as any) : ref
}
toRef
该函数判断对象属性值是 ref对象 的情况下,返回对象属性值,否则返回 ObjectRefImpl实例。可提供 defaultValue 用于对象属性值未定义的情况
ObjectRefImpl实例 通过 getter/setter 代理访问对象属性值,取值操作 o.p 等于 (toRef(o, 'p')).value;赋值操作 o.p = v 等于 (toRef(o, 'p')).value = v。对 普通对象属性 使用 toRef 生成的对象,不具备响应式操作
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue?: T[K]
): ToRef<T[K]> {
const val = object[key]
return isRef(val)
? val
: (new ObjectRefImpl(object, key, defaultValue) as any)
}
class ObjectRefImpl<T extends object, K extends keyof T> {
public readonly __v_isRef = true
constructor(
private readonly _object: T,
private readonly _key: K,
private readonly _defaultValue?: T[K]
) {}
get value() {
// 获取对象属性值
const val = this._object[this._key]
return val === undefined ? (this._defaultValue as T[K]) : val
}
set value(newVal) {
// 设置对象属性值
this._object[this._key] = newVal
}
}
toRefs
该函数接收一个响应式对象,然后创建一个相同原始类型的对象,将每个属性值进行 toRef 处理并赋值到新的对象上,最后返回该对象
export function toRefs<T extends object>(object: T): ToRefs<T> {
if (__DEV__ && !isProxy(object)) {
console.warn(`toRefs() expects a reactive object but received a plain one.`)
}
const ret: any = isArray(object) ? new Array(object.length) : {}
for (const key in object) {
ret[key] = toRef(object, key)
}
return ret
}
核心API
ref
该函数判断传入值是 ref对象 的情况下,直接返回传入值,否则返回 RefImpl实例
RefImpl实例 初始化时会使用 toRaw 函数获取传入值的原始值(非响应式对象)并且赋值到 _rawValue 属性,用于调用 setter时 判断 ref对象 是否需要更新值;然后使用 toReactive 函数将传入值转化为响应式对象并且赋值到 _value 属性,它就是 getter/setter 操作的属性
在之后访问操作 refInstance.value 时,会调用 trackRefValue 收集 ReactiveEffect实例添加到 dep 属性;赋值操作 refInstance.value = v 时,_rawValue 对比不同后会更新 _rawValue 与 _value 值并且调用 triggerRefValue 通知依赖此实例的 ReactiveEffect实例,从而实现响应式操作
export function ref(value?: unknown) {
return createRef(value, false)
}
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined /* ReactiveEffect实例集合 */
public readonly __v_isRef = true
constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)
}
get value() {
trackRefValue(this)
return this._value
}
set value(newVal) {
newVal = this.__v_isShallow ? newVal : toRaw(newVal)
// const hasChanged = (v, oV) => !Object.is(v, oV)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = this.__v_isShallow ? newVal : toReactive(newVal)
triggerRefValue(this, newVal)
}
}
}
进阶API
shallowRef
该函数与先前的 ref函数 类似,只是在 赋值 _rawValue 和 _value 时,不进行 toRaw 和 toReactive 操作
triggerRef
该函数用于手动触发依赖函数的调用。如果依赖函数包含渲染函数,就相当于进行强制更新
export function triggerRef(ref: Ref) {
triggerRefValue(ref, __DEV__ ? ref.value : void 0)
}
customRef
该函数传递一个工厂函数,返回 CustomRefImpl实例
CustomRefImpl 初始化时提供 工厂函数 两个函数参数:第一个参数用于 何时追踪依赖函数;第二个参数用于 何时通知依赖函数执行。要求 工厂函数 返回一个包含 get 和 set 属性的对象,在操作 getter/setter 时使用
export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
return new CustomRefImpl(factory) as any
}
class CustomRefImpl<T> {
public dep?: Dep = undefined
private readonly _get: ReturnType<CustomRefFactory<T>>['get']
private readonly _set: ReturnType<CustomRefFactory<T>>['set']
public readonly __v_isRef = true
constructor(factory: CustomRefFactory<T>) {
const { get, set } = factory(
() => trackRefValue(this),
() => triggerRefValue(this)
)
this._get = get
this._set = set
}
get value() {
return this._get()
}
set value(newVal) {
this._set(newVal)
}
}