由于上一篇文章已经写过reactive,所以ref就只需要考虑原始类型即可,引用类型只需要引进上一篇文章的reactive来实现引用类型的响应式。
reactive的手写
手写ref
其实我们在使用reactive和ref时一般考虑个人习惯,不过引用类型数据多时建议使用reactive。但是ref写起来简单还通用,ref是完胜reactive的。
ref函数
与reactive同样的人,ref开局出生就是独生子
js
export function ref(val){//将原始类型数据变成响应式 引用类型也可以
return createRef(val)
}
createRef
这里我们先判断val.__v_isRef
是否为响应式,开始数据不会是响应式的,所以得先执行下面RefImpl类里面的操作
js
function createRef(val){
// 判断val是否已经是响应式
if(val.__v_isRef){
return val
}
// 将val变成响应式
return new RefImpl(val)
}
RefImpl类
我们写ref当然不能只写它对原始类型有用,必须也能使用引用类型。这时就得从reactive那里借点东西过来了 reactive的手写。ref也需要进行依赖收集。
js
class RefImpl{
constructor(val){ //class类的语法
//ref代理的对象身上的属性
this.__v_isRef = true //给每一个被ref操作过的属性值添加标记
this._value = convert(val)
}
get value(){ //age.value可以获取
//为this对象做依赖收集
track(this,'value')
return this._value
}
//更新age
set value(newVal){
if(newVal !== this._value){
this._value = convert(newVal)
trigger(this,'value')//触发掉'value'上的所有副作用函数
}
}
}
function convert(val){
if(typeof val!=='object' || val === null ){
return val
}else{
return reactive(val)
}
}
this._value = convert(val)
:这行代码将传入的val
值进行转换,并将转换后的值存储在_value
属性中。convert
函数的作用是判断val
的类型,如果是对象类型,则将其转换成响应式对象,否则保持原来的类型。通过将值存储在_value
属性中,可以在后续的代码中通过get value()
方法来获取该值。get value()
:这是使用了JavaScript 中的特殊属性访问器,可以通过age.value来获取ref里面的数据,而不是age.value(),简化了代码set value
:当数据发送更新后,先通过convert判断数据类型,再通过reactive里面的trigger函数触发value里面所有副作用函数。