Stores
Der klassische Svelte-Weg für geteilten Zustand: ein Objekt mit .subscribe, das du im Markup bequem mit dem $-Präfix liest.
Was ist ein Store?
Ein Store ist einfach ein Objekt mit einer .subscribe-Methode.
Er hält einen Wert, und jeder Interessent kann sich benachrichtigen lassen, wenn sich dieser
Wert ändert. Weil ein Store ein ganz normaler JavaScript-Wert ist, kannst du ihn aus einem
Modul exportieren und in beliebig vielen Komponenten verwenden — genau das macht ihn zum
Werkzeug für komponentenübergreifenden Zustand.
import { writable } from 'svelte/store';
// Ein Store ist ein Objekt mit einer .subscribe-Methode.
export const zaehler = writable(0);Svelte bringt drei Fabrik-Funktionen mit: writable (les- und schreibbar), readable (nur lesbar) und derived (aus anderen Stores abgeleitet).
Das $-Präfix: automatische Subscription
Der eigentliche Komfort liegt im Markup: Schreibst du einem Store-Namen ein $ voran, abonniert Svelte den Store automatisch, liest seinen aktuellen Wert und meldet sich beim
Zerstören der Komponente sauber wieder ab. Kein manuelles subscribe/unsubscribe nötig.
<script>
import { zaehler } from './stores.js';
</script>
<!-- $-Präfix = automatische Subscription im Markup -->
<p>Wert: {$zaehler}</p>
<button onclick={() => $zaehler++}>+1</button>💡 $store ist Lesen UND Schreiben
{$zaehler} liest den Wert. Eine Zuweisung wie $zaehler++ oder $zaehler = 5 im Script ruft intern .set(...) auf. Das $-Präfix funktioniert nur
in .svelte-Dateien — in normalen .js/.ts-Dateien
nutzt du die Methoden direkt.
set, update, subscribe und get
Außerhalb des Markups arbeitest du mit den Methoden des Stores:
import { get } from 'svelte/store';
zaehler.set(10); // Wert direkt setzen
zaehler.update((n) => n + 1); // Wert aus dem alten berechnen
const wert = get(zaehler); // einmalig auslesen (ohne Subscription)
// Manuell abonnieren — gibt eine unsubscribe-Funktion zurück:
const stop = zaehler.subscribe((n) => console.log('neu:', n));
stop(); // wieder abmelden (im Markup macht das $ automatisch).set(wert)— setzt einen neuen Wert..update(fn)— berechnet den neuen Wert aus dem alten (z. B. Hochzählen)..subscribe(fn)— ruftfnsofort und bei jeder Änderung auf; gibt eine Funktion zum Abmelden zurück.get(store)— liest den Wert genau einmal aus (praktisch, aber sparsam einsetzen: kein reaktives Abonnement).
Live ausprobieren
Die folgende Demo nutzt echte Stores aus dieser Seite: ein writable namens zaehler und ein daraus abgeleitetes derived namens verdoppelt. Beide werden im Markup mit $ gelesen.
$zaehler = 0 · abgeleitet $verdoppelt = 0
readable & derived
Ein readable ist ein Store, den nur seine eigene Start-Funktion füttert — von
außen kannst du ihn ausschließlich lesen. Ideal für Werte, die aus einer Quelle „ticken"
(Uhr, WebSocket, Geolocation):
import { readable } from 'svelte/store';
// readable: von außen nur lesbar. Der zweite Parameter ist eine
// Start-Funktion; sie bekommt "set" und gibt eine Aufräum-Funktion zurück.
export const uhrzeit = readable(new Date(), (set) => {
const id = setInterval(() => set(new Date()), 1000);
return () => clearInterval(id); // beim letzten Abmelden aufräumen
});Ein derived-Store berechnet seinen Wert automatisch aus einem oder mehreren
anderen Stores neu — vergleichbar mit $derived bei den Runes, nur eben auf
Store-Ebene:
import { writable, derived } from 'svelte/store';
export const preis = writable(100);
export const menge = writable(3);
// Aus einem Store ableiten:
export const doppelt = derived(preis, ($preis) => $preis * 2);
// Aus mehreren Stores ableiten (Array als erstes Argument):
export const summe = derived(
[preis, menge],
([$preis, $menge]) => $preis * $menge
);Einordnung zu Rails
🛤️ Rails-Vergleich: geteilter, reaktiver Zustand im Client
In Rails lebt „Zustand" typischerweise in Session, Datenbank oder Redis und wird pro Request frisch geladen — ein Snapshot, der bis zur
nächsten Anfrage eingefroren ist. Ein Store ist das clientseitige Gegenstück, aber reaktiv: Der Wert lebt im Browser weiter, und jede Komponente, die $store liest, aktualisiert sich sofort bei einer Änderung — ganz ohne neuen
Request oder Reload.
# Rails: ein Wert, der prozessweit "lebt" und beobachtet wird,
# ist hier eher untypisch — Zustand steckt in Session/DB/Redis
# und wird pro Request frisch geladen.
class CartController < ApplicationController
def show
@total = current_cart.items.sum(&:price) # Snapshot pro Request
end
endZusammenfassung
💡 Das Wichtigste
writable/readable/derivederzeugen Stores; ein Store ist ein Objekt mit.subscribe.- Im Markup liest du mit
$store(Auto-Subscription inkl. Aufräumen). .set/.update/.subscribesteuern den Store im Code;get(store)liest einmalig.- Stores sind heute besonders für async/„RxJS-artige" Fälle und die
$app/storesvon SvelteKit relevant — für simplen geteilten State sind oft Runes-Module (nächste Lektion) die schlankere Wahl.
🎯 Probier es selbst
Ergänze einen zweiten writable-Store faktor und ein derived([zaehler, faktor], ([z, f]) => z * f). Zeige das Ergebnis im Markup
mit $ an und beobachte, wie es auf Änderungen beider Stores reagiert.