【vue设计与实现】原始值的响应式方案 3-自动脱ref

toRefs函数解决了响应丢失的问题,同时也带来新的问题。由于toRefs会把响应式数据的第一层属性值转换为ref,因此必须通过value属性访问值,这样增加了用户的心智负担,因为通常情况下用户是在模板中访问数据的,用户肯定不希望编写下面这样的代码

<p>{{foo.value}} / {{bar.value}}</p>

因此需要有自动脱ref的能力,自动脱ref指的是如果读取的属性是一个ref,则直接将该ref对应的value属性值返回,也就是无须通过newObj.foo.value来访问值,只需要通过newObj.foo就能返回值。
要实现这个功能,需要使用Proxy为newObj创建一个代理对象,通过代理来实现,如下面代码所示:

function proxyRefs(target){
	return new Proxy(target,{
		get(target,key,receiver){
			const value = Reflect(target,key,receiver)
			// 自动脱ref实现,如果读取的值是ref,则返回它的value属性值
			return value._v_isRef?value.value:value
		}
	})
}

// 调用proxyRefs函数创建代理
const newObj = proxyRefs({...toRefs(obj)})

这样就实现了自动脱ref:

console.log(newObj.foo) //1
console.log(newObj.bar) //2

实际上,在编写Vue.js组件时,组件中的setup函数返回的数据会传递给proxyRefs函数进行处理:

const MyComponent = {
	setup(){
		const count = ref(0)
		
		// 返回的这个对象会传递给proxyRefs
		return {count}
	}
}

相应的,设置属性的值也应该有自动为ref设置值的能力,实现起来也很简单,只需要添加对应的set拦截好桉树即可:

function proxyRefs(target){
	return new Proxy(target,{
		get(target,key,receiver){
			const value = Reflect(target,key,receiver)
			// 自动脱ref实现,如果读取的值是ref,则返回它的value属性值
			return value._v_isRef?value.value:value
		}
		set(target, key, newValue, receiver){
			// 通过target读取真实值
			const value = target[key]
			// 如果值是Ref,则设置其对应的value属性值
			if(value._v_isRef){
				value.value = newValue
				return true
			}
			return Reflect.set(target, key, newValue, receiver)
		}
	})
}

自动脱ref不仅存在于上述场景,reactive函数也有自动脱ref的能力,如下面代码所示:

const count = ref(0)
const obj = reactive({count})
obj.count //0

可以看到obj.count本应该是一个ref,但是由于有自动脱ref的能力在,所以不需要通过value属性就能读取ref的值,这样设计减少了用户的心智负担,可以不用关心哪些是ref,哪些不是ref

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值