provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

说人话就是如果你把对象都改了那这个改动就追踪不到了,如果你就改了个对象属性那这种响应就能追踪到。以下是具体的代码分析。

这意味着,出于某种考虑,vue故意将provide/inject设定为不可响应的。也就是说如果你的provide的数据改变,inject是不会接受到这个改变,然而如果你provide的内容是一个可响应的数据,比如一个对象引用,那么这个对象的属性是可以检测到变化的。举例来说:

provide(){
  return{
    foo:this.msg
  }
},
data() {
  return {
    msg: "hello",
  }
}
mounted(){
  setTimeout(()=>{
    this.msg = "world";
  },3000)
}

而此时你在子组件中去监测:

inject:{
    foo: { default: {} }
}

就会发现不管父组件的foo怎么更改,子组件的foo都不会改变。
而如果你改变的不是对象,而是对象的属性,那么这个改变就可以被监测,举例来说:

provide(){
  return{
    foo: this.msg
  }
},
data() {
  return {
    msg: {
        bar: 'hello'
    }
  }
}
mounted(){
  setTimeout(()=>{
    this.msg.bar = "world";
  },3000)
}

那么此时子组件就可以监听到属性的变动。
这里有一个重点,这个属性更改是以引用不变前提下的属性更改,如果引用变动了,那就是对象改变而不是对象的属性改变了。举个例子:

mounted(){
  setTimeout(()=>{
      // 这种情况下叫改变了属性,属性的更改是可以响应的
    this.msg.bar = "world";
    // 这种情况就是对对象的重新赋值,也就是把对象引用都改了,这种是不可响应的
    this.msg = {
        bar: 'world'
    }
  },3000)
}

看到了响应式的问题已经解决了,inject也确实会随着provide的属性变更而改变数据。
但是怀着打破砂锅问到底的方针,这种改变是否可以被本地监测呢?像这样data和computed数据是可响应的吗?如下:

data() {
    return {
      data: this.boardData.data
    };
  },
  inject: {
    boardData: { default: {} }
  },
  computed: {
    data1() {
      return this.boardData.data;
    }
  }

经过严谨的实验,答案是不能,因此尽管号称inject/provide是类似于props这种父子组件传值的,祖孙组件传值,但是实现方式并不相同。
结果如下:

因此需要用的inject的计算值的时候还是直接算,不要指望能用computed取返回响应的计算值了

Logo

一站式 AI 云服务平台

更多推荐