Vue2 注入 provide inject

前言

vue中的provide可以进行父组件向后代组件进行传值。但是,他没办法监听传输数据的变化。或者说明白点,就是如果我在父组件改变注入的值,它没办法更新。子组件改变传入的值,它也没办法进行更新。
vue官方说明

图片说明文字

问题

我们经过测试发现:

// 父组件
provide: function() {
    this.myData3 = Vue.observable({
      val: "我没改变",
    });
    return {
      myData1: this.myData1, //非响应
      myData2: this.myData2, //响应
      myData3: this.myData3, //响应
    };
},
data() {
    return {
      myData1: "我没改变",
      myData2: {
        val: "我没改变",
      },
    };
},
methods: {
    change(){
      this.myData1 = "我改变了" // 触发后不能改变
      this.myData2.val = "我改变了" // 触发后能改变
      this.myData3.val = "我改变了" // 触发后能改变
      // 触发后不能改变
      this.myData2 = {
        val: "我改变了",
      } 
      // 触发后不能改变
      this.myData3 = {
        val: "我改变了",
      } 
    },
}


// 孙组件
 inject: ["myData1", "myData2", "myData3"],

以上这几种方式都无法响应和对一整个对象赋值的改变,并且watch和computed也无法监听到一整个对象赋值的改变,只能响应和监听某个对象中的属性改变,这不符合我们的使用习惯,我们希望可以对一整个对象赋值并监听它的改变

如果我们希望整个数据都是响应式的。那么可以通过以下方法实现:

我们可以让provide提供一个函数。函数内部返回一个响应式的数据。此时整条数据的响应式的状态并不会丢失。

而且这样做有一个好处,即无法直接修改myData4 的值,因为他是一个计算属性。这样就可以避免数据的混乱。

解决

关键代码如下:

// 父组件
provide: function () {
    return {
      myData4: () => this.myData4, //响应
    };
},
data() {
    return {
      myData4: {
        val: "我没改变",
      },
    };
 },
methods: {
    change() {
      // 触发后能改变
      this.myData4 = {
        val: "我改变了",
      };
    },
},


// 孙组件
inject: ["myData4"],
computed: {
    computedMyData4() {
      return this.myData4()
    }
},
watch: {
    computedMyData4(val) {
      console.log("我是孙组件,我监听到了myData4改变", val);
    },
},