Wenn ein Wert in mehreren Komponenten gebraucht wird, gibt es in Svelte drei Mechanismen: Props für direkte Eltern-Kind-Beziehungen, Context für hierarchische Vererbung im Komponenten-Baum, Stores (oder ein globaler $state-Container) für App-weite Werte. Sie sind nicht austauschbar — jeder hat eine Sweet Spot. Dieser Artikel hilft, sich klar zu entscheiden.

Die drei Mechanismen kurz im Überblick

MechanismusReichweiteWer setzt?Wer liest?
PropsGenau ein Eltern → ein direktes KindEltern beim AufrufKind via $props()
ContextEine Komponente → alle ihre NachfahrenEltern via setContextBeliebige Nachfahren via getContext
Store / globaler $stateApp-weit, beliebige StellenWer den Wert importiertWer den Wert importiert

Faustregel zum Einprägen: Props sind der Standard. Context ist für Werte, die in tiefen Bäumen gebraucht werden. Stores oder globaler $state sind für Werte, die nichts mit der Komponenten-Hierarchie zu tun haben.

Beispiel-Szenario: Theme-Wechsel

Stell dir vor, deine App hat einen Theme-Toggle und alle Komponenten sollen sich entsprechend einfärben. Wie löst du das?

Variante 1 – Mit Props

svelte Eltern reicht durch
<Layout {theme}>
    <Sidebar {theme}>
        <SidebarItem {theme}>

        </SidebarItem>
    </Sidebar>
</Layout>

Funktioniert, ist aber Prop-Drilling pur. Jede Zwischenkomponente muss theme durchreichen, auch wenn sie nichts damit anfängt. In einer großen App wird das schnell unhaltbar.

Variante 2 – Mit Context

svelte App.svelte
<script>
    import { provideTheme } from '$lib/contexts/theme.svelte';
    const theme = provideTheme();
</script>

<Layout>
    <Sidebar>
        <SidebarItem />
    </Sidebar>
</Layout>

Layout, Sidebar und SidebarItem müssen theme nicht kennen. Nur die Komponenten, die das Theme tatsächlich brauchen, holen es per useTheme() aus dem Context. Sauberer Datenfluss, klar markierte Konsumenten.

Variante 3 – Mit globalem $state

ts src/lib/state/theme.svelte.ts
export const theme = $state({ value: 'light' as 'light' | 'dark' });
svelte Beliebige Komponente
<script>
    import { theme } from '$lib/state/theme.svelte';
</script>

<div class={`box theme-${theme.value}`}>…</div>

Auch das funktioniert. Die Komponente muss noch nicht mal in einem bestimmten Baum stehen — sie importiert den State direkt aus dem Modul.

Welche Variante ist richtig?

Für einen App-weiten Theme-Toggle wären sowohl Variante 2 (Context) als auch Variante 3 (globaler State) vertretbar. Variante 2 ist sauberer, wenn du theoretisch mehrere Themes parallel haben willst (z. B. ein Modal, das immer light bleibt) — weil Context hierarchisch ist, kann ein Sub-Baum einen anderen Wert haben. Variante 3 ist kompakter, wenn das Theme tatsächlich global ist und nie pro Bereich anders.

Variante 1 (Props) ist hier eindeutig die schlechteste Wahl — der Wert wird auf der Wurzel gesetzt und an Blättern gelesen, dazwischen ist er nur Ballast.

Gegenbeispiel: Wann Props gewinnen

Stell dir eine Listen-Komponente vor, die ihre Items rendert. Jedes Item bekommt sein Datum als Prop. Würde man das per Context lösen?

svelte Übertrieben
{#each items as item (item.id)}
    <ListItem>
        {#snippet …}
            <!-- Item bezieht sich auf einen Context, den die List-Komponente
                 pro Iteration neu setzen müsste — das ist nicht möglich -->
        {/snippet}
    </ListItem>
{/each}

Funktioniert nicht sauber: Context wird einmal pro Komponenten-Setup gesetzt, nicht pro Iteration. Hier ist die Prop die einzig richtige Lösung:

svelte Richtig
{#each items as item (item.id)}
    <ListItem {item} />
{/each}

Pro Item wird die Komponente mit ihrem eigenen item-Wert aufgerufen. Direkt, lesbar, kein Trick.

Wann Stores statt Context?

Beide können „über Komponenten hinweg geteilte Werte” abbilden. Der Unterschied liegt im Gültigkeitsbereich:

  • Context ist an die Komponenten-Hierarchie gebunden. Eine Komponente außerhalb des Baums sieht den Wert nicht. Tests, die eine Komponente isoliert mounten, müssen den Context manuell nachliefern.
  • Stores und globale $state-Container sind app-weit. Jede Datei kann sie importieren, jeder Test bekommt automatisch den selben Wert (und ggf. dessen Verschmutzung aus vorherigen Tests).

Daraus folgen zwei Faustregeln:

  • Context für Werte, die zu einer Komponenten-Instanz gehören oder zu einem Sub-Baum. Beispiel: Eine <Form> und ihre <Field>-Kinder, eine <Tabs> und ihre <TabPanel>-Kinder.
  • Store / globaler $state für Werte, die zu einer App-Instanz gehören. Beispiel: Auth-Status, Spracheinstellung, Toast-Manager.

Das Theme-Beispiel von oben ist ein Grenzfall — beides ist defensible. In der Praxis wird ein Theme-Wechsel oft per globalem State gelöst, weil er ohnehin nur einmal pro App existiert.

Entscheidungsbaum

Beim Verteilen eines Wertes diese Fragen der Reihe nach:

FrageWenn ja → nimm
Wird der Wert nur ein Komponenten-Level tief gebraucht?Prop
Wird er in einem klar abgegrenzten Sub-Baum gebraucht (Form, Tabs)?Context
Wird er von vielen voneinander unabhängigen Komponenten gebraucht und ist app-weit eindeutig?Globaler $state / Store
Soll er pro Sub-Baum unterschiedlich sein (geschachtelte Themes etc.)?Context (mehrfach gesetzt)

Wenn du dich nicht entscheiden kannst, ist Props meist der sicherere Default. Context und globalen State führt man bewusst ein, sobald Prop-Drilling spürbar lästig wird.

Patterns aus der Praxis

Auth-Status → globaler $state in .svelte.ts. Auth ist app-weit eindeutig, jede Komponente kann ihn unabhängig vom Baum konsumieren.

Theme → meist globaler $state. Wenn geschachtelte Themes nötig sind, dann Context.

Form-Validierung → Context. Eine <Form>-Komponente und ihre <Field>-Kinder gehören klar zusammen, mehrere Forms in der App sollen sich nicht stören.

Toast/Snackbar-Manager → globaler $state plus Custom DOM Event. Jede Komponente kann einen Toast auslösen, der Container hört zentral darauf.

Theme der aktuellen Modal-Schicht → Context. Hier gewinnt die hierarchische Variante deutlich, weil ein Modal eigene Theme-Regeln haben kann.

Locale / Sprache → globaler $state. App-weit identisch, nur ein Wert relevant.

API-Client (HTTP-Instance) → Context, falls eine Library die API-Instanz pro Komponente unterschiedlich konfigurieren können soll. Sonst globaler State.

Häufige Stolperfallen

Context als Ersatz für globalen State. Wenn jede Komponente in der App den Wert braucht, ist ein globaler $state direkter — kein setContext-Aufruf in einer Wurzel-Komponente nötig, kein Test-Setup.

Globaler State als Ersatz für Props. Wenn nur eine Komponente den Wert braucht und einmal ändert, ist eine Prop oder lokaler $state klarer als ein App-weites Modul.

Context-Wert wird in einer Geschwister-Komponente erwartet. Geschwister sehen den Context nicht. Der Context muss bei einem gemeinsamen Vorfahren gesetzt werden.

Globalen State zwischen mehreren App-Instanzen oder SSR-Requests teilen. Auf dem Server (SvelteKit) ist globaler State gefährlich: Mehrere Requests teilen sich denselben Modul-Speicher, was zu Cross-Request-Datenleaks führen kann. Auth-Status, Locale und ähnliches gehören dort in request-spezifischen Kontext (z. B. event.locals plus Context).

Tests laufen nicht, weil Context fehlt. Wenn du eine einzelne Komponente isoliert testest, hat sie keinen Eltern-Komponenten, der setContext aufruft. Lösung: Testumgebung mit einem Test-Wrapper-Komponent setzen, der den Context vorbefüllt.

Weiterführende Ressourcen

Externe Quellen

Verwandte Artikel

/ Weiter

Zurück zu Context API

Zur Übersicht