Provide / Inject
Daten durch den Komponentenbaum tunneln — ohne Props-Drilling.
Das Problem: Props-Drilling
Wenn eine tief verschachtelte Komponente Daten braucht, müsstest du diese Props durch jede Zwischenebene durchreichen — auch wenn die Zwischenkomponenten die Daten selbst gar nicht nutzen. Das nennt man Props-Drilling.
<!-- ❌ Props-Drilling: Jede Ebene muss "theme" weiterreichen -->
<GrandParent :theme="theme"> <!-- hat theme -->
<Parent :theme="theme"> <!-- braucht es nicht, reicht nur weiter -->
<Child :theme="theme"> <!-- braucht es nicht, reicht nur weiter -->
<DeepChild :theme="theme" /> <!-- braucht es endlich! -->
</Child>
</Parent>
</GrandParent>Rails-Vergleich: Helper-Methoden & Concerns
In Rails nutzt du helper_method :current_user in Controllern, damit Views und Partials überall auf current_user zugreifen können — ohne es durch jedes Partial als Local durchzureichen. provide/inject löst dasselbe Problem in Vue.
Daten bereitstellen mit provide()
provide() macht einen Wert für alle Nachkommen einer Komponente verfügbar — egal wie tief verschachtelt.
<script setup lang="ts">
import { provide, ref } from 'vue'
const theme = ref('dark')
// Alle Nachkommen können 'theme' injecten
provide('theme', theme)
// Auch Funktionen bereitstellen
provide('toggleTheme', () => {
theme.value = theme.value === 'dark' ? 'light' : 'dark'
})
</script>
<template>
<div :class="theme">
<slot />
</div>
</template>Daten empfangen mit inject()
Jede Nachkommen-Komponente kann mit inject() auf bereitgestellte Werte zugreifen. Der zweite Parameter ist ein Fallback-Wert.
<script setup lang="ts">
import { inject } from 'vue'
// Wert empfangen mit Fallback
const theme = inject('theme', ref('light'))
const toggleTheme = inject<() => void>('toggleTheme')
</script>
<template>
<button
:class="theme === 'dark' ? 'bg-gray-800' : 'bg-white'"
@click="toggleTheme?.()"
>
Theme wechseln ({{ theme }})
</button>
</template>Inject nur in Nachkommen
inject() findet nur Werte, die von einer Eltern-Komponente (oder App-Level) bereitgestellt wurden. Geschwister-Komponenten sehen die Werte nicht.
Typsicherheit mit InjectionKey
Vue bietet InjectionKey<T> als typsicheren Schlüssel. So vermeidest du String-basierte Keys und bekommst volle Autovervollständigung.
import type { InjectionKey, Ref } from 'vue'
// Typsicherer Key — generisch typisiert
export const themeKey: InjectionKey<Ref<string>> = Symbol('theme')
export interface ThemeContext {
theme: Ref<string>
toggleTheme: () => void
}
export const themeContextKey: InjectionKey<ThemeContext> = Symbol('themeContext')<script setup lang="ts">
import { provide, inject } from 'vue'
import { themeContextKey } from '~/keys'
// Provider
const theme = ref('dark')
provide(themeContextKey, {
theme,
toggleTheme: () => {
theme.value = theme.value === 'dark' ? 'light' : 'dark'
},
})
// Consumer (in anderer Komponente)
const ctx = inject(themeContextKey)
// ctx ist automatisch typisiert als ThemeContext | undefined
ctx?.toggleTheme()
</script>Reaktive Werte bereitstellen
Damit Nachkommen auf Änderungen reagieren, solltest du ref() oder computed() über provide weitergeben — nicht nur statische Werte.
<script setup lang="ts">
import { provide, ref, readonly, computed } from 'vue'
const count = ref(0)
// ✅ Reaktiver Wert — Nachkommen sehen Änderungen
provide('count', readonly(count))
// ✅ Computed — wird automatisch aktualisiert
provide('doubleCount', computed(() => count.value * 2))
// ✅ Setter-Funktion bereitstellen
provide('increment', () => count.value++)
// ❌ NICHT: provide('count', count.value)
// → Verliert Reaktivität! Nur der initiale Wert wird übergeben.
</script>readonly() für Sicherheit
Wenn Nachkommen den Wert nicht ändern sollen, wickle ihn in readonly() ein. So bleibt der Einweg-Datenfluss gewahrt.
App-Level Provide
In Nuxt kannst du Werte app-weit über ein Plugin bereitstellen. So sind sie in jeder Komponente verfügbar.
// plugins/theme.ts
export default defineNuxtPlugin((nuxtApp) => {
const theme = useState('theme', () => 'light')
// App-weit bereitstellen
nuxtApp.vueApp.provide('appTheme', theme)
nuxtApp.vueApp.provide('setTheme', (newTheme: string) => {
theme.value = newTheme
})
})Interaktive Demo
Simulierter Theme-Provider: Die Eltern-Komponente stellt ein Farbthema bereit, das alle verschachtelten Komponenten automatisch verwenden.
Beachte: Keine einzige Zwischenkomponente (LayoutWrapper, ContentArea) musste das Theme als Prop empfangen. provide/inject tunnelt direkt durch.
Zusammenfassung
Kernpunkte
provide()stellt Daten für alle Nachkommen bereitinject()empfängt die Daten — egal wie tief verschachteltInjectionKey<T>sorgt für Typsicherheit- Reaktive Werte (
ref/computed) providieren, nicht statische readonly()schützt vor ungewollten Änderungen durch Nachkommen- App-Level Provide über Nuxt-Plugins für globale Werte nutzen