在使用vue3中,使用reactive
创建的对象或者数组进行赋值时,可以正常赋值,但是不会触发响应式变化。
let obj = {
name:张三,
age:23
}
let reactive = reaciive({})
reactive = obj // 可以正常赋值,但是不能响应式变化
原因
- vue3官方文档说明:
reactive() 返回一个对象的响应式代理
- 为什么不生效: 每次直接把一个对象或者数组赋值给
reactive
创建的对象或数组时,导致reactive创建的响应式对象被新赋值的直接代理,再vue3中操作的都是proxy代理对象,所以失去了响应式 - 在vue3中不管是对象还是数组都不能直接将整个数据进行赋值,这样会造成reactive定义的响应式失效
- 通俗说: 就像对象的地址被替换,就不是原来的那个对象了
解决方法
不是直接赋值,包裹一层
- 可以直接对它对对象内进行赋值,不是重新赋值,不会失去响应式
let obj = reactive{
arr: [1,2,3]
})
obj.arr = [4,5,6] // 还是响应式
直接使用ref
ref赋值时,包裹了一层对象
let arr = reactive([1,2,3])
let arr1 = ref([1,2,3]) // ref重新赋值时,通过.value赋值
为什么会这样
vue3的响应式原理是通过es6的proxy
实现的
- proxy 的使用本身就是对于 对象的拦截, 通过
new Proxy
的返回值,触发get和set方法,es6的Reflect
(反射),动态对被代理对象的相应属性进行特定的操作 proxy
是基于对象的拦截,如果本身是个原始值时,就拦截不到,失去了,所以ref本身实现响应式会使用.value
let obj = {
name: "许七安",
age: 23,
wife: {
name: "洛玉衡",
},
hobby: ["勾栏听曲", "插花弄玉"],
};
let proxy = new Proxy(obj, {
get: function (target, key) {
console.log("触发get");
return Reflect.get(target, key);
},
set: function (target, key, value) {
console.log("触发set");
return Reflect.set(target, key, value);
},
});
console.log((proxy.name = "许银锣"));
console.log((proxy.wife.name = "慕楠栀")); // 当修改更深的一层对象时,不会触发set事件,但是会修改
console.log(proxy);
发现当嵌套一层时,不会触发响应式事件,无法拦截下来,所以这个时候就需要嵌套一层
let obj = {
name: "许七安",
age: 23,
wife: {
name: "洛玉衡",
},
hobby: ["勾栏听曲", "插花弄玉"],
};
function reactive(obj) {
return new Proxy(obj, {
get: function (target, key) {
console.log("触发get");
// 判断如果是个对象在包装一次,实现深层嵌套的响应式
if (typeof target[key] === "object") {
return reactive(target[key]);
};
return Reflect.get(target, key);
},
set: function (target, key, value) {
console.log("触发set");
return Reflect.set(target, key, value);
},
});
}
const proxy = reactive(obj)
console.log((proxy.name = "许银锣"));
console.log((proxy.wife.name = "慕楠栀")); // 这样就可以监听到set
console.log(proxy);
这样就是.value
嵌套一层实现响应式监听