Provide And Inject in Vue.js
Provide and Inject are the advanced concepts of Vue.js Components module. It’s not mostly needed for small structured components. But imagine if the structures are deeply nested. Then we are in need to pass data from parent to innermost child component. It’s a completely difficult situation right now.
To solve this problem, Vue.js introduced Provide and Inject concepts. Here the parent component provides the dependency to all its children irrespective of how long the component hierarchy is. As the name suggests, the parent component has a provide option and the child component has an inject option. The provide option will provide the data and inject will acquire this data.
Let’s take a deep dive into this with an example. Read Components in Vue3 and Single File Components Vue 3 if you are new to Vue.js components.
Root
└─ Page (<- Use Provide Here ->)
├─ App Bar
└─ Layout
├─ Drawer Menu
└─ Main Floor
└─ Header Room (<- Use Inject Here ->)
└─ Content Room
└─ Footer
Let me take the above example, where we want Page component data in Header room component. We can pass as prop data from Page -> Layout -> Main Floor -> Header Room components one by one. Alternatively we can use provide/inject here.
Use Provide
Firstly, our goal is to pass Page Component data to it’s inner child Header Room Component without passing as prop data. So we are using Provide in Page.vue.
Page.vue
<template>
<div />
<!-- <AppBar />
// Here we supposed to pass pageProperties
// to Layout and Layout -> Main Floor -> Header Room
// But with the help of provide/inject we can directly
// use this in Header Room component -->
<Layout />
</template>
<script>
import Layout from "./Layout";
export default {
components: {
Layout,
},
provide: {
pageProperties: {
pageName: "Provide/Inject",
pageVersion: "1.0.0",
pageUser: "admin",
},
},
};
</script>
Use Inject
Secondly, we will be using inject in HeaderRoom.vue Component to get the data given in Page.vue Component with provide option.
HeaderRoom.vue
<template>
<div>Page Name : {{ pageProperties.pageName }}</div>
<div>Page Name : {{ pageProperties.pageVersion }}</div>
<div>Page Name : {{ pageProperties.pageUser }}</div>
</template>
<script>
export default {
inject: ["pageProperties"],
};
</script>
The full working example
Note :
Some points to be noted here,
- Parent component wouldn’t know which child is going to use the provided data.
- Likewise the child component wouldn’t be aware where the injected data coming from.
Provide And Inject in Vue.js with Composition API
In addition, we can use provide and inject in the composition API also. We have to call both methods inside the setup function.
Provide in setup
We have to import provide function from vue module. The provide function has two parameters,
- The Property Name (type should be string)
- The Property Value (type can be anything)
we are updating Page.vue component as follows,
Page.vue
<template>
<div />
<!-- <AppBar />
// Here we supposed to pass pageProperties
// to Layout and Layout -> Main Floor -> Header Room
// But with the help of provide/inject we can directly
// use this in Header Room component -->
<Layout />
</template>
<script>
import { provide } from "vue";
import Layout from "../provideinject/Layout";
export default {
components: {
Layout,
},
setup() {
provide("pageProperties", {
pageName: "Provide/Inject",
pageVersion: "1.0.0",
pageUser: "admin",
});
},
};
</script>
Inject in setup
We have to import the inject function from the vue module. The inject function has two parameters,
- The property Name
- Default value (optional)
we are updating HeaderRoom.vue component as follows,
HeaderRomm.vue
<template>
<div>Page Name : {{ pageProperties.pageName }}</div>
<div>Page Name : {{ pageProperties.pageVersion }}</div>
<div>Page Name : {{ pageProperties.pageUser }}</div>
</template>
<script>
import { inject } from "vue";
export default {
setup() {
let pageProperties = inject("pageProperties");
return {
pageProperties,
};
},
};
</script>
The full working example
Provide And Inject in Vue.js with Reactivity
In the above example, pageProperties will not be reactive by default. Moreover, They are not reactive by nature. We have to use ref/reactive with provide to make it reactive.
Note that, In the below example we are using reactive with provide to make pageProperties reactive. Here updateVersion method is provided to all it’s children with pageProperties.
Page.vue
<template>
<div />
<!-- <AppBar />
// Here we supposed to pass pageProperties
// to Layout and Layout -> Main Floor -> Header Room
// But with the help of provide/inject we can directly
// use this in Header Room component -->
<Layout />
</template>
<script>
import { provide, reactive } from "vue";
import Layout from "./Layout";
export default {
components: {
Layout,
},
setup() {
let pageProperties = reactive({
pageName: "Provide/Inject",
pageVersion: "1.0.0",
pageUser: "admin",
});
provide("pageProperties", pageProperties);
provide("updateVersion", () => {
pageProperties.pageVersion = "2.0.0";
});
return {
pageProperties,
};
},
};
</script>
After that, we are going to update the version from HeaderRoom Component with the help of inject directly.
HeaderRoom.vue
<template>
<div>
<button @click="updateVersion">Update Parent Version</button>
</div>
<div>Page Name : {{ pageProperties.pageName }}</div>
<div>Page Name : {{ pageProperties.pageVersion }}</div>
<div>Page Name : {{ pageProperties.pageUser }}</div>
</template>
<script>
import { inject } from "vue";
export default {
setup() {
let pageProperties = inject("pageProperties");
let updateVersion = inject("updateVersion");
return {
pageProperties,
updateVersion,
};
},
};
</script>
So we can update parent component data(pageProperties version) from the child component using provide and inject concepts in Vue.js effectively.
The full working example
Global Provider – Provide Application API
However, we can use provide as a global provider to all components. The provided data would be injected to all it’s components within the application. It’s an alternative way for global properties in Vue.js.
Let me show you the example below,
index.js
const app = Vue.createApp({});
// Global Provider
app.provide("appProperties", {
user: "admin",
appVersion: "1.0.0"
});
// Page Component where contains content component
app.component("Page", {
template: `<Content />`
});
// Content component where inject used to get
// global properties
app.component("Content", {
inject: ["appProperties"],
template: `
<div>User Name : {{ appProperties.user }}</div>
<div>Version : {{ appProperties.appVersion }}</div>
`
});
index.html
<div id="app">
<Page />
</div>
Here the appProperties
is provided to all components within the application. We got the data in the Content component using inject.
The full working example
Conclusion
- In conclusion, Provide and inject makes ease of data communication between parent and it’s child components.
- Provide and Inject are not reactive by nature. But we can make it reactive with the help of reactive/ref.
- We can use provide as global provider instead of global properties in Vue.js