Learn How to Use Vue Provide Inject

Vue provide/inject allows us to avoid prop drilling, when we encounter a condition where we would need to pass a prop down to a deeper component with the multiple-level component. This is where Vue provide/inject comes to solve the problems, the parent component needs only to provide the data and the deeper descendant component just injects the provided value from its parent and we can access the value directly without having to pass multi prop down the component.

Vue provide/inject

Here we will provide a sample of how we can use provide/inject to pass down the data to a deeper component without having to use props multiple times. As long as the component is the descendant of the “provide” component we can use the “provide” value no matter how deep the component is.

Here in the <HelloWorld /> component, we want to provide the “content” to its descendant component.

In the <HelloWorld /> page

<template>
  <div style="border: 1px solid grey; padding: 8px">
    Hello world
    <input type="text" v-model="content" />
    <ChildA />
    <ChildB />
  </div>
</template>

<script>
import ChildA from '@/components/ChildA';
import ChildB from '@/components/ChildB';

export default {
  components: {
    ChildA,
    ChildB,
  },
  data() {
    return {
      content: 'content',
    };
  },
  provide() {
    return {
      content: this.content,
    };
  },
};
</script>

In the <ChildA /> component

<template>
  <div style="border: 1px solid grey; padding: 8px; margin: 8px">
    Child A
    <DeepChildA />
  </div>
</template>

<script>
import DeepChildA from '@/components/DeepChildA';

export default {
  components: {
    DeepChildA,
  },
};
</script>

Then in the <DeepChildA /> component, we want to access the “provide” value by “inject” it into the component.

In the <DeepChildA /> component

<template>
  <div style="border: 1px solid grey; padding: 8px; margin: 8px">
    Deep Child A
    <p>Inject: {{ this.content }}</p>
  </div>
</template>

<script>
export default {
  inject: ['content']
}
</script>

Injects are resolved before the component's own state so we can access injected properties in data.

In the <ChildB /> component

<template>
 <div style="border: 1px solid grey; padding: 8px; margin: 8px">
  Child B
  <p>Inject: {{ this.injectedContent }}</p>
 </div>
</template>

<script>
export default {
 inject: ['content'],
 data() {
  return {
   injectedContent: this.content,
  };
 },
};
</script>

Reactivity Vue 2 (Vue 3 below)

In Vue 2 provide/inject are not reactive from his documentation it is intentional however we want to pass an object to achieve reactively.

In the <HelloWorld /> page

<template>
  <div style="border: 1px solid grey; padding: 8px">
    Hello world
    <input type="text" v-model="content.first" />
    <ChildA />
    <ChildB />
  </div>
</template>

<script>
import ChildA from '@/components/ChildA';
import ChildB from '@/components/ChildB';

export default {
  components: {
    ChildA,
    ChildB,
  },
  data() {
    return {
      content: {
        first: 'content',
      },
    };
  },
  provide() {
    return {
      content: this.content,
    };
  },
};
</script>

In the <ChildA /> component

<template>
 <div style="border: 1px solid grey; padding: 8px; margin: 8px">
  Child A
  <DeepChildA />
 </div>
</template>

<script>
import DeepChildA from '@/components/DeepChildA';

export default {
 components: {
  DeepChildA,
 },
};
</script>

Then in the <DeepChildA /> component, we can see the data is reactive according to its parent state.

In the <DeepChildA /> component

<template>
 <div style="border: 1px solid grey; padding: 8px; margin: 8px">
  Deep Child A
  <p>Inject: {{ this.content.first }}</p>
 </div>
</template>

<script>
export default {
 inject: ['content'],
};
</script>

Reactivity Vue 3

However in Vue 3 to achieve reactivity we can take advantage of computed API. See the example below.

<template>
 <div style="border: 1px solid grey; padding: 8px">
  Hello world
  <input type="text" v-model="content" />
  <ChildA />
  <ChildB />
 </div>
</template>

<script>
import ChildA from '@/components/ChildA';
import ChildB from '@/components/ChildB';

export default {
 components: {
  ChildA,
  ChildB,
 },
 data() {
  return {
   content: 'content',
  };
 },
 provide() {
  return {
   content: computed(() => this.content),
  };
 },
};
</script>

Conclusion

As has been demonstrated Vue provide inject allowing us to pass data down to descendant component with multiple levels deep without having to declare multiple props. We also can achieve data reactivity by passing an object in Vue 2 and taking advantage of computed API in Vue 3.