JAVASCRIPT
Deep Component Communication using `provide` and `inject`
Understand how to avoid prop drilling in Vue 3 by using `provide` and `inject` for passing data down deeply nested components efficiently.
// src/App.vue
<template>
<div class="app">
<h1>Theme Provider</h1>
<button @click="toggleTheme">Toggle Theme</button>
<GrandparentComponent />
</div>
</template>
<script setup>
import { ref, provide } from 'vue';
import GrandparentComponent from './components/GrandparentComponent.vue';
const theme = ref('light');
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
};
// Provide the theme and a function to toggle it
provide('appTheme', theme);
provide('toggleTheme', toggleTheme);
</script>
// src/components/GrandparentComponent.vue
<template>
<div class="grandparent">
<h2>Grandparent Component</h2>
<ParentComponent />
</div>
</template>
<script setup>
import ParentComponent from './ParentComponent.vue';
</script>
// src/components/ParentComponent.vue
<template>
<div class="parent">
<h3>Parent Component</h3>
<ChildComponent />
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
</script>
// src/components/ChildComponent.vue
<template>
<div :class="['child', injectedTheme]">
<h4>Child Component</h4>
<p>Current Theme: {{ injectedTheme }}</p>
<button @click="injectedToggleTheme">Change Theme (from Child)</button>
</div>
</template>
<script setup>
import { inject, computed } from 'vue';
// Inject the provided theme and toggle function
const injectedTheme = inject('appTheme');
const injectedToggleTheme = inject('toggleTheme');
// Optional: a computed property reacting to the injected theme
const currentThemeDisplay = computed(() => {
return injectedTheme.value.charAt(0).toUpperCase() + injectedTheme.value.slice(1);
});
</script>
<style>
.app.light, .child.light { background-color: #f0f0f0; color: #333; padding: 10px; margin: 10px 0; border-radius: 5px; }
.app.dark, .child.dark { background-color: #333; color: #f0f0f0; padding: 10px; margin: 10px 0; border-radius: 5px; }
.grandparent, .parent, .child { border: 1px solid #ccc; padding: 10px; margin: 10px; border-radius: 5px; }
</style>
How it works: This example demonstrates `provide` and `inject` in Vue 3 for sharing data across deeply nested components without 'prop drilling'. The `App.vue` component `provide`s a reactive `theme` and a `toggleTheme` function. Any descendant component, like `ChildComponent.vue`, can then `inject` these values directly, regardless of how many intermediate components exist. This pattern is ideal for global settings, themes, or any data that needs to be available to an entire component subtree without explicitly passing it through every single prop in the hierarchy.