Context API
Zustand, der einen Komponenten-Teilbaum durchreicht — ohne Prop-Drilling und ohne echte Globalität.
Wozu Context?
Manchmal soll ein Wert vielen tief verschachtelten Komponenten zur Verfügung stehen, ohne ihn
durch jede Zwischenebene als Prop durchzureichen („Prop-Drilling"). Genau dafür gibt es die Context API: Eine Elternkomponente legt mit setContext(key, wert) etwas ab, und jede beliebig tief liegende Nachfahr-Komponente holt es mit getContext(key) wieder heraus.
<script>
import { setContext } from 'svelte';
import Kind from './Kind.svelte';
let farbe = $state('teal');
// Nur während der Komponenten-Initialisierung aufrufbar!
// Getter-Objekt bereitstellen -> Kinder sehen den LIVE-Wert.
setContext('theme', {
get farbe() { return farbe; },
setFarbe(f) { farbe = f; }
});
</script>
<Kind />
<button onclick={() => farbe = 'crimson'}>Ändern</button><script>
import { getContext } from 'svelte';
// Holt den Wert vom nächsten Vorfahren, der ihn gesetzt hat.
const theme = getContext('theme');
</script>
<p style="color: {theme.farbe}">Ich erbe die Farbe vom Elternteil</p>Baum-lokal statt global
Der entscheidende Unterschied zum Modul-State der letzten Lektion: Context ist an den Komponenten-Baum gebunden. getContext findet immer den Wert des nächstgelegenen Vorfahren, der ihn gesetzt hat. Renderst du dieselbe Elternkomponente
zweimal, hat jede ihren eigenen, isolierten Context — anders als ein Modul, von dem es
app-weit nur eine Instanz gibt.
⚠️ Nur während der Initialisierung
setContext und getContext dürfen nur synchron
während der Initialisierung einer Komponente aufgerufen werden — also im <script>-Top-Level, nicht in einem Event-Handler, Callback oder setTimeout. Danach ist der Context-Baum bereits aufgebaut.
💡 Reaktiv bleiben: Getter statt Rohwert
setContext selbst ist nicht reaktiv — es reicht einen Wert einmalig weiter.
Willst du, dass Kinder Änderungen mitbekommen, legst du (wie beim Modul-State) ein Objekt mit Gettern in den Context, dessen Felder $state lesen.
Live ausprobieren
Diese Seite ruft in ihrem eigenen <script> sowohl setContext (mit einem Getter auf einen $state-Namen) als auch getContext auf. Änderst du den Namen im Feld, sieht der über Context gelesene
Wert die Änderung sofort — weil ein Getter durchgereicht wurde:
Über getContext gelesen: Anna
Typsichere Schlüssel
Als Schlüssel taugt jeder Wert; ein Symbol ist ideal, weil es garantiert
kollisionsfrei ist. In TypeScript hinterlegst du außerdem den Typ des Werts, damit getContext nicht unknown zurückgibt:
// context-keys.ts — typsichere Schlüssel mit Symbol
import type { Writable } from 'svelte/store';
export interface UserCtx {
get name(): string;
logout(): void;
}
// Symbol als Schlüssel: garantiert kollisionsfrei
export const USER = Symbol('user');Typische Anwendungsfälle
- Theme für einen bestimmten Bereich (z. B. ein dunkles Panel innerhalb einer hellen Seite).
- Formular: eine
<Form>-Komponente stellt Validierungs- und Registrierungs-Funktionen bereit, die alle<Field>-Kinder nutzen. - i18n: die aktuelle Sprache/Übersetzungsfunktion für einen Layout-Teilbaum.
- Komponentenbibliotheken (Tabs, Accordion), die Zustand mit ihren Unterteilen teilen.
ℹ️ Context vs. Modul-State — wann was?
Nimm Modul-State (.svelte.ts), wenn es den Wert app-weit nur
einmal geben soll (Theme der ganzen App, eingeloggter Nutzer). Nimm Context,
wenn derselbe „Slot" pro Teilbaum unterschiedlich belegt sein darf und der Wert nicht global
sichtbar sein soll.
Einordnung zu Rails
🛤️ Rails-Vergleich: request-lokale Weitergabe
Context verhält sich wie request-lokale Instanzvariablen in Rails: Was der
Controller in @article legt, steht der View und über yield/content_for auch verschachtelten Layouts zur Verfügung — aber nur für diesen einen Request-„Baum", nicht
prozessweit. Genauso reicht setContext einen Wert an alles darunter durch, ohne
echte Globalität.
# Rails: request-lokale Instanzvariablen fließen vom Controller
# in die View und über yield/content_for in verschachtelte Layouts.
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id]) # nur für DIESEN Request-Baum
end
endZusammenfassung
💡 Das Wichtigste
setContext(key, wert)(Eltern) undgetContext(key)(Nachfahren) reichen Werte durch den Baum — ohne Prop-Drilling.- Beide nur während der Komponenten-Initialisierung aufrufbar.
- Baum-lokal, nicht global: jede Eltern-Instanz hat ihren eigenen Context.
- Für Reaktivität ein Getter-Objekt durchreichen;
Symbol+ Typ machen den Schlüssel sicher.
🎯 Probier es selbst
Baue eine <Tabs>-Komponente, die per setContext die aktuell
aktive Tab-ID (als Getter) und eine select(id)-Funktion bereitstellt. Lass
mehrere <Tab>-Kinder per getContext erkennen, ob sie aktiv
sind — ganz ohne Props zwischen ihnen.