【Vue3源码实现】Ref isRef unRef proxyRefs实现

前言

在上篇文章中 我们了解了响应式原理,并在最后实现了reactive。
上文链接Vue3响应式原理实现与track和trigger依赖收集和触发依赖
在我们的日常业务中,我们有可能需要将一个基础数据类型的值也转换成响应式的,而reactive只能代理对象,我们需要对基础数据类型的值也进行读写操作的拦截,但 Proxy 无法实现对基础数据类型值读写操作的拦截。
所以Vue设计了Ref,以及相关api
本篇文章实现下Ref及相关API isRef ,unRef,proxyRefs

先来列举下实现ref需要注意的几点

ref在script标签中必须.value才能使用 在template标签中则不用
ref既能代理原始数据,又能代理对象数据,还可以同时代理原始数据与对象数据,
如果参数是一个对象的话,ref的内部会使用 reactive 对参数进行一层转化封装

先实现下它.value这个东西,在vue源码中是将ref的值包裹在一个RefImp类中实现的

class RefImp {

private _value: any;

constructor(value) {

// 判断 value 值是不是对象,如果是对象,则用 reactive 包裹

this._value = isObject(value) ? reactive(value) : value;

}

get value() {

// 直接返回 _value

return this._value;

}

set value(value) {

// 设置 _value

this._value = value;

}

}

function ref(value) {

return new RefImp(value);

}
//试验一波
const obj = { a: 1 };
const refObj = ref(obj); console.log(refObj.value); // 输出: { a: 1 }
接下来实现ref的响应式
export class RefImp {
private _value: any;
public dep: any;
constructor(value) {
// / 看看value 是不是一个对象,如果是一个对象的话则转为响应式对象

this._value = isObject(value) ? reactive(value) : value
this.dep = new Set()
}
get value() {
TrackEffects(this.dep)
return this._value
}
set value(newvalue) {
// 检查新值是否发生变化
if (!Object.is(newvalue,_value)) {
this._value = isObject(newValue) ? reactive(newValue) : newValue
TriggerEffect(this.dep)
}
}
}
// `TrackEffects` 函数用于追踪依赖关系,而 `TriggerEffect` 函数用于触发相关效果。
//这是从track和trigger中抽离出来的
function TrackEffects(dep: any) {
if (!dep.has(activeEffect)) {
	dep.add(activeEffect)
	activeEffect.deps.push(dep)
}
}
export function TriggerEffect(dep) {
for (const effect of dep) {
effect.run()
}
}

优化下代码,因为_value可能被reactive修改为Proxy对象,

新传入的值不可能相等,所以需要有个rawValue存储原来的传入的value与newValue对比

export class RefImp {
...
private rawValue: any;
...
constructor(value) {
this.rawValue = value
...
}
set value(newValue){
	if(!Object.is(newValue,this.rawValue)){
	this.rawValue = newValue
	this._value = isObject(newValue) ? reactive(newValue) : newValue
	...
	}
}
}

isRef

检查某个值是否为 ref。我们可以在refImp类中加入属性来判断

class refImp{
public _v_isRef = true;
...
}
function isRef(value){
	return !!value._v_isRef
}

unRef

如果参数是 ref对象,则返回内部值,否则返回参数本身。

function(value){
	return isRef(value) ? value.value : value 
}

proxyRefs

前言我们说到有一点 为什么template中不需要.value,
因为Vue使用 proxyRefs 来处理响应式引用的模板解析。proxyRefs 是一个内部函数,用于处理模板中的响应式引用。它会将传入的响应式引用对象转换为代理对象,从而在模板中直接访问引用的属性时能够自动获取其 value 属性的值
接下来实现它

export function proxyRefs(objectWithRefs) {

return new Proxy(objectWithRefs, {

get(target, key) {

return unRef(Reflect.get(target, key))

},

set(target, key, value) {

if (isRef(target[key]) && !isRef(value)) {

return target[key].value = value

} else {

return Reflect.set(target, key, value)

}

}

})

}

文章到这里就结束了,希望对你有所帮助。

你可能感兴趣的:(vue.js,javascript,前端,数据结构,前端框架,开发语言)