One of the ways to pass some data from parent to child components is through props. But how do we pass data from a parent to a really deeply nested child component? Of course, we can use props. But we’ll be passing props to intermediate components as well which don’t even need it. The intermediate components will be used to only pass the props to even more nested components.
Props drilling vs Provide / Inject
For instance, if we had three components named ParentComponent, ChildComponent, and ChildComponentNested. And we wanted to some props data from ParentComponent to ChildComponenNested, we could pass data in the following manner:
- ParentComponent sends props X -> ChildComponent receives props X
- ChildComponent sends received props X -> ChildComponentNested receives props X
We can start to see the problem here. We’re kinda being forced to pass props twice instead of once. A better way would be to be able to pass props from the ParentComponent to ChildComponentNested directly.
This is where provide and inject comes into action. We can declare any local state data globally accessible using the provide method. The provider will make the state accessible to all the components (descendant components) in the app. We can then import the data into any descendant component we want using the inject method.
Provide / Inject example code
Here’s our ParentComponent.vue file containing the ChildComponent and also a reactive state named loggedInUser which contains some data:
<script setup>
import { reactive, provide } from 'vue';
import ChildComponent from './ChildComponent.vue';
const loggedInUser = reactive({
displayName: 'Gautam',
email: 'gautam@example.com'
})
provide('loggedInUser', loggedInUser)
</script>
<template>
<div>
<h1>Parent component</h1>
<h3>
Logged in user: {{ loggedInUser.displayName }}
</h3>
<ChildComponent />
</div>
</template>
<style>
.child-component {
border: 1px solid rgb(138, 138, 138);
padding: 24px;
margin: 10px 0;
}
</style>
Code language: HTML, XML (xml)
You can see that we’ve used provide method in line 10 to make the loggedInUser reactive state globally accessible.
Now, here’s ChildComponent containing the ChildComponentNested component:
<script setup>
import ChildComponentNested from './ChildComponentNested.vue';
</script>
<template>
<div class="child-component">
<h2>Child component</h2>
<ChildComponentNested />
</div>
</template>
Code language: HTML, XML (xml)
As you can see in the above file, we’re not passing any props to the ChildComponentNested either. Now, here’s the ChildComponentNested.vue file:
<script setup>
import { inject } from 'vue'
const loggedInUser = inject('loggedInUser')
</script>
<template>
<div class="child-component">
<h2>Nested child component</h2>
<div class="user-display-name">
User: {{ loggedInUser.displayName }}
</div>
</div>
</template>
<style>
.user-display-name {
color: green;
font-size: 24px;
background-color: darkseagreen;
padding: 2px 12px;
margin: 4px 0;
}
</style>
Code language: HTML, XML (xml)
In the above file, we’re accessing the reactive state loggedInUser using the inject method at line 4. We’ve then displayed the state value on line 12.
Here’s what the output of the above code would look like:
If you have any doubts or suggestions, comment in the comment section below!