Search code examples
vue.jsvuejs2vue-component

How to create reactive provide/inject


note version: vuejs2 composition api

as shown in the below posted code, in the parent component, i provide the value of the reactive variable status. in mounted lifecycle callback i change the value of status every specific amount of time. in the child component, i inject the value of status as demonstrated below in the code.

at run time, i expected that log statement in

watch:{
    injStatus(newVal, oldVal) {
      console.log({msg:' watched injStatus. oldVal:' + oldVal + ', and newVal: ', newVal});
    },
  },

to be displayed with different values for the status variable, but that does not happen.

please let me know how to make provid/inject reactive

url to attempts:

click here please

parent

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld></HelloWorld>
</template>
<script>
import {computed} from 'vue'
import {InjectionKeys} from './assets/InjectionKeys.js'
import {HelloWorld} from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  },
  data() {
        return {
          status:undefined
        };
      },
    provide() {
        return {
            [InjectionKeys.PROVIDE_KEY_STATUS.description]: computed(() => this.compPropsStatus),
        };
    },
    computed:{
      compPropsStatus() {
        return this.status
      },
    },
    mounted() {
      setTimeout(() => {
          this.status = '1'
        }, 1000);
      
        setTimeout(() => {
          this.status = '2'
        }, 3000);
      
        setTimeout(() => {
          this.status = '3'
        }, 5000);

        setTimeout(() => {
          this.status = '4'
        }, 7000);
    }
}
</script>

child:

<script>
import {InjectionKeys} from '../assets/InjectionKeys.js'

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  inject: {
        injStatus: { from: InjectionKeys.PROVIDE_KEY_STATUS.description },
    },
  watch:{
    injStatus(newVal, oldVal) {
      console.log({msg:' watched injStatus. oldVal:' + oldVal + ', and newVal: ', newVal});
    },
  },
    
}
</script>

Solution

  • Options and composition API is combined, this may lead to the undetermined result. A is just reactive object with value property, can be created manually and then be passed by reference:

    data: () => ({
      status: { value: null }
    }),
    provide() {
        return {
            PROVIDE_KEY_STATUS: this.status
        };
    },
    mounted() {
        this.status.value = 1;
        ...
    

    In a child:

    inject: {
        injStatus: { from: 'PROVIDE_KEY_STATUS' },
    },
    watch: { ['injStatus.value'](newVal, oldVal) {...}, ...
    

    With composition API, this can be wrapped with composables:

    const useProvideStatus = statusRef => provide('PROVIDE_KEY_STATUS', statusRef);
    
    const useStatus = () => inject('PROVIDE_KEY_STATUS');