美文网首页学习
Vue.js中[provide/inject]

Vue.js中[provide/inject]

作者: CodeMT | 来源:发表于2022-09-14 11:15 被阅读0次

官方是这么解释的,provide / inject这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

说通俗点,就是可以用来父辈们给祖孙传值,请看清楚,这里说的是可以隔代传值,传统的props只能父传子,这个不一样无论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,这就是它最大的特性。

基本语法

provide 选项应该是:一个对象或返回一个对象的函数
inject 选项应该是:一个字符串数组,或 一个对象,对象的 key 是本地的绑定名

认真看清楚这两句话,然后来看下面示例。

父组件中提供

provide() {
  return {
    map_nodeObj: { map_node: this.obj }
    // 提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
  }
}

子组件中引入

inject: {
  map_nodeObj: {
    default: () => {
      return {map_node: '0'}
    }
  }
},
// 使用: this.map_nodeObj.map_node

上面inject就是对象,当然也可以是下面这样

inject: {
  inject: ['map_nodeObj']
},

代码执行顺序

data
provide
created  // 在这个阶段$el还未生成,在这先处理privide的逻辑,子孙组件才可以取到inject的值
mounted
...

小结

这么做也是有明显的缺点的,在任意层级都能访问导致数据追踪比较困难,不知道是哪一个层级声明了这个或者不知道哪一层级或若干个层级使用了,因此这个属性通常并不建议使用,能用vuex的使用vuex,不能用的多传参几层,但是在做组件库开发时,不对vuex进行依赖,且不知道用户使用环境的情况下可以很好的使用。
因此,官方说provideinject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。


Vue.js中provide/inject实现响应式数据更新

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

示例(最终没有更新)

首先假设我们在祖辈时候传入进来是个动态的数据,官方不是说如果你传入了一个可监听的对象,那么其对象还是可响应的么?

parent父页面:

export default {
  provide(){
    return {foo:this.fonnB}
  },
  data(){
    return {fonnB:'old word'}  
  }
  created() {
    setTimeout(()=>{
      this.fonnB = "new words";    // 这里更新新,仅仅foonB变化了,foo没有变化
      this._provided.foo = "new words";
      //这里更新foo变化了,但子组件获得的foo 依旧是old words
      console.log(this._provided)
    },1000)
  },
}

child子页面:

export default {
  inject:['foo'],
  data(){
    return {chilrfoo:this.foo}  
  }    
}

结果

结果通过通过上面方式,经过验证,子组件页面都没办法实现响应更新this.foo的值。可能我们对官方理解还是有误,下面通过网上资料和自己构思实现了响应式数据更新

示例(结果可行)

很明显上面再父组件定时器内我们是改变了数据源,这个时候我们就在想,我们改变的数据到底有没有传入到子孙组件中,那么要验证这个问题,我们不妨可以在子孙组件中手动写set 函数,computed 本身就只相当于一个get函数,当然,你也可以试试watch

parent父页面:

export default {
  provide(){
    return {foo:this.fonnB}
  },
  data(){
    return {
      fonnB:{a:'old word'}
    }  
  }
  created() {
    setTimeout(()=>{
      this.fonnB.a="new words";    
      //这种更新 foo变化了,但子组件获得的foo  依旧是old words
    },1000)
  },
}

child子页面:

export default {
  inject:['foo'],
  data(){
    return {
      childfooOld:this.foo.a
    }  
  },
  computed:{
    chilrfoo(){
      return  this.foo.a
    }
  }    
}

相关文章