浅析ref和reactivetoRefs响应式原理及reactive创建的响应式对象
解构后。。。
⼀、reactive 创建的响应式对象解构后为什么会失去响应式
Vue 拥有⼀个响应式系统,可以让它在数据更新的时候⾃动进⾏视图的更新。在Vue3.0中,可以使⽤ reactive 声明响应式状态。⽂档说不要解构 reactive 创建的响应式对象,为什么?因为会失去响应式的功能,那为什么会失去,我们就来简单研究下。
1、进⼊reactive⽅法:
reactive vue3
可以看到它在内部调⽤了createReactiveObject⽅法,这名字很好理解就是创建响应式对象,调试进去:
它在这⾥做了⼀些处理,细节暂时不探究,重点在这:
创建了⼀个代理对象将其保存在内部并返回,学习Vue3或多或少都听过Vue3如何进⾏数据视图更新的,Proxy对数据进⾏了拦截,当数据发⽣变化,通知Vue进⾏视图变化。
可以看出 reactive ⽅法其实就是创建了⼀个Proxy对象,以及进⾏了⼀系列处理,其中并没有到它可能会失去响应式的情况,也就是说它失去响应式不在于Vue⽽是在于Proxy对象本⾝,那么可以简化⼀下。
2、Proxy 解构
(1)Proxy 解构基本对象
const obj = {
count: 1
};
const proxy = new Proxy(obj, {
get(target, key, receiver) {
console.log("这⾥是get");
(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("这⾥是set");
return Reflect.set(target, key, value, receiver);
}
});
我们可以看到不解构的话,count 赋值 2 可以做到响应式更改。⽽解构赋值,count 就是 5 ,proxy 还是 { count: 2 }
是因为解构相当于重新赋值给另⼀个变量的原因吗,也就是说它变成了⼀个新值。
(2)Proxy 解构嵌套对象:我们再看下嵌套对象
const obj = {
a: {
count: 1
}
};
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
console.log("这⾥是get");
if (typeof target[key] === "object") {
return reactive(target[key]);
};
(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("这⾥是set");
return Reflect.set(target, key, value, receiver);
}
});
};
const proxy = reactive(obj);
(1)直接赋值:proxy 有响应变化
(2)解构⼀次:proxy 也有响应变化
(3)解构2次到底:proxy 不再响应变化
(4)总结原因:为什么会不同,其实很好理解,只解构⼀次,其实新的对象的 count 仍然是被代理的,
⽽解构两次,直接获取了count,相当于绕过了代理 a,直接拿到基本类型的值。
那么就很好理解了,解构为什么会失去响应,⽤这个图就可以解释:
因为解构赋值相当于直接跳过了代理那⼀层,在下⾯直接获取值,所以 get 和 set ⽆法被调⽤。
⼆、ref 和 reactive + toRefs 响应式实现原理
对于基本数据类型,函数传递或者对象解构时,会丢失原始数据的引⽤。换⾔之,我们没法让基本数据类型,或者解构后的变量(如果它的值也是基本数据类型的话),成为响应式的数据。
我们没办法让 a 或 x 这样的基本数据类型成为响应式的数据的,Proxy 也⽆法劫持基本数据。
但是有时候,我们确实就是想⼀个数字、⼀个字符串是响应式的,或者就是想利⽤解构的写法。那怎么办呢?只能通过创建⼀个对象,也即是源码中的 Ref 数据,然后将原始数据保存在 Ref 的属性value当中,再将它的引⽤返回给使⽤者。
既然是我们⾃⼰创造出来的对象,也就没必要使⽤ Proxy 再做代理了,直接劫持这个 value 的 get/set
即可,这就是 ref 函数与 Ref 类型的由来。
不过单靠 ref 还没法解决对象解构的问题,它只是将基本数据保持在⼀个对象的 value 中,以实现数据响应式。对于对象的解构还需要另外⼀个函数:toRefs。通过遍历对象,将每个属性值都转成 Ref 数据,这样解构出来的还是 Ref 数据,⾃然就保持了响应式数据的引⽤。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论