vue3中reactive赋值,不能响应式变化

20,660 阅读2分钟

在使用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嵌套一层实现响应式监听