今天来实现一下ref的功能函数,isRef与unRef
isRef和isReactive一样,都是用于检测数据类型,isRef是检测是不是一个ref对象,跟isReactive函数实现起来一样,我们先来写一个单元测试
这里要实现的功能是,检测ref对象肯定就通过返回true,检测普通类型数据以及reactive对象都是false
it("it should return a boolean", () => {
let obj = ref(1)
let a = 1
let b = reactive({ user: 1 })
expect(isRef(obj)).toBe(true)
expect(isRef(a)).toBe(false)
expect(isRef(b)).toBe(false)
})
我们在ref.ts中把逻辑写好,首先肯定要返回一个isRef的函数对象,接着我们读取某个属性,如果是ref,那么可以读到,如果不是ref那么它没有这个属性,就会为false
class RefImpl {
private _value
private _raw
public dep
//是否是ref的标识
public __v_isRef = true
constructor(value) {
//保存没有代理前的value
this._raw = value
//做对象类型检测
this._value = isObject(value) ? reactive(value) : value
this.dep = new Set()
}
get value() {
trackRefValue(this.dep)
return this._value
}
set value(newValue) {
if (!isHasChanged(this._raw, newValue)) return
this._raw = newValue
this._value = newValue
tiggerEffect(this.dep)
}
}
我们用一个__v_isRef来标识ref,当我们能读到这个属性是那么肯定就是ref对象了
export function isRef(value) {
return !!value.__v_isRef
}
为什么要用!!转义呢,因为当我们传入的数据比如是1 a {name: 1}这种不是响应式对象 以及reactive对象,他们身上就没有__v_isRef属性,返回值是undefined,因此用!!转义一下,变成布尔值
在 Vue 3 中,unRef用于获取一个可能是响应式对象或 ref 对象的原始值,以避免对响应式对象的重复包装或 ref 对象的.value访问, 如果不是一个ref对象的话也返回它的值,先来看一下单测
it("it should return a value", () => {
let obj = ref(2)
let a = 1
expect(unRef(obj)).toBe(2)
expect(unRef(a)).toBe(1)
})
我们想一下思路。当我们传入的是ref对象时,我们返回.value即可,若不是ref对象那好办,直接返回它的值
我们来实现一下, 我们只用检测一下是不是ref即可,上面的isRef刚好可以检验
export function unRef(ref) {
return isRef(ref) ? ref.value : ref
}
这样代码就已经都实现啦,是不是很容易了,我们在写源码的过程中一定要理清楚逻辑关系
最近博客已经往掘金迁移了,希望大家也能多多支持在掘金的博客创作,与君共勉!
掘金主页