JAVASCRIPT

Implementing Dependency Injection with Provide/Inject

Implement Vue 3's `provide` and `inject` to manage shared data across deeply nested components, avoiding prop drilling and improving maintainability.

// App.vue (Parent Component)
<template>
  <div>
    <h1>Parent Component</h1>
    <p>Shared Message: {{ parentMessage }}</p>
    <IntermediateComponent />
  </div>
</template>

<script setup>
import { ref, provide } from 'vue';
import IntermediateComponent from './IntermediateComponent.vue';

const parentMessage = ref('Hello from the App!');

// Provide a value that can be injected by any descendant component
// 'messageKey' is a unique identifier (symbol recommended for larger apps)
provide('messageKey', parentMessage);
provide('countKey', 123);

// You can also provide reactive data directly
const reactiveData = ref({ user: 'Alice', theme: 'dark' });
provide('reactiveDataKey', reactiveData);

// To make the provided data update, you'd update parentMessage.value
// setTimeout(() => {
//   parentMessage.value = 'Message updated after 3 seconds!';
// }, 3000);
</script>

// IntermediateComponent.vue
<template>
  <div style="border: 1px dashed gray; padding: 10px; margin-left: 20px;">
    <h3>Intermediate Component</h3>
    <p>This component doesn't need the message directly, but passes through.</p>
    <ChildComponent />
  </div>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue';
</script>

// ChildComponent.vue
<template>
  <div style="border: 1px solid purple; padding: 10px; margin-left: 20px;">
    <h4>Child Component</h4>
    <p>Injected Message: {{ injectedMessage }}</p>
    <p>Injected Count: {{ injectedCount }}</p>
    <p>Injected Reactive User: {{ injectedReactiveData.user }}</p>
    <p>Injected Reactive Theme: {{ injectedReactiveData.theme }}</p>

    <button @click="injectedReactiveData.theme = (injectedReactiveData.theme === 'dark' ? 'light' : 'dark')">
      Toggle Theme
    </button>
  </div>
</template>

<script setup>
import { inject } from 'vue';

// Inject the value provided by an ancestor using its key
const injectedMessage = inject('messageKey', 'Default Message'); // 'Default Message' is optional fallback
const injectedCount = inject('countKey');
const injectedReactiveData = inject('reactiveDataKey');

// When injected data is a ref, it needs .value to be accessed/mutated.
// If the provide()'d value itself was a ref, inject() will return the ref.
// If the provide()'d value was a plain object, inject() will return that plain object.
// console.log(injectedMessage.value); // Access the value of the ref
</script>
How it works: This snippet showcases Vue 3's `provide` and `inject` features, a pattern for dependency injection that allows data to be passed down through a component tree without explicit prop drilling. The parent component uses `provide` to make a reactive value available using a key (`'messageKey'`, `'countKey'`, `'reactiveDataKey'`). Any descendant component, regardless of how deep, can then use `inject` with the same key to access that value. This significantly improves maintainability for deeply nested components by decoupling them from intermediate props, especially useful for themes, user data, or global configurations.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs