JAVASCRIPT
Avoiding Prop Drilling with Vue 3 `provide` and `inject`
Understand how Vue 3's `provide` and `inject` functions enable efficient data sharing between deeply nested components without cumbersome prop drilling.
// ParentComponent.vue
<template>
<div>
<h1>Parent Component</h1>
<button @click="toggleTheme">Toggle Theme</button>
<IntermediateComponent />
</div>
</template>
<script setup>
import { ref, provide, readonly } from 'vue';
import IntermediateComponent from './IntermediateComponent.vue';
const currentTheme = ref('light');
const toggleTheme = () => {
currentTheme.value = currentTheme.value === 'light' ? 'dark' : 'light';
};
// Provide a reactive value (and a way to update it, if needed)
// Using readonly to prevent child components from directly modifying currentTheme
provide('theme-key', readonly(currentTheme));
provide('toggle-theme-key', toggleTheme);
</script>
// IntermediateComponent.vue
<template>
<div class="intermediate">
<h2>Intermediate Component</h2>
<p>I don't need the theme, but I pass through.</p>
<GrandchildComponent />
</div>
</template>
<script setup>
import GrandchildComponent from './GrandchildComponent.vue';
</script>
<style scoped>
.intermediate {
border: 1px dashed #ccc;
padding: 10px;
margin: 10px 0;
}
</style>
// GrandchildComponent.vue
<template>
<div :class="['grandchild', theme]">
<h3>Grandchild Component</h3>
<p>Current Theme: {{ theme }}</p>
<button @click="toggleTheme">Toggle Theme (from Grandchild)</button>
</div>
</template>
<script setup>
import { inject } from 'vue';
// Inject the provided values
const theme = inject('theme-key');
const toggleTheme = inject('toggle-theme-key');
</script>
<style scoped>
.grandchild {
padding: 15px;
border-radius: 8px;
margin-top: 10px;
}
.grandchild.light {
background-color: #e0f2f7;
color: #333;
}
.grandchild.dark {
background-color: #333;
color: #f0f0f0;
}
</style>
How it works: `provide` and `inject` in Vue 3 offer a dependency injection system, allowing a parent component to provide data that can be injected by *any* descendant component, regardless of how deep it is in the component hierarchy. This eliminates 'prop drilling' – passing props through many intermediate components that don't directly need them. Here, `ParentComponent` provides `currentTheme` and a `toggleTheme` function. `GrandchildComponent` directly injects and uses these values without `IntermediateComponent` needing to know about them.