$effect — Seiteneffekte
Für alles, was über reinen State hinausgeht: DOM manipulieren, Timer setzen, loggen, in localStorage schreiben oder externe Bibliotheken ansteuern — automatisch bei jeder relevanten Änderung.
Was ist ein Seiteneffekt?
$state hält Zustand, $derived leitet Werte ab — beide bleiben
innerhalb deiner Komponente. Ein Seiteneffekt ist alles, was mit der
Außenwelt spricht: den Dokumenttitel setzen, einen Timer starten, in localStorage schreiben, eine Chart-Bibliothek aktualisieren oder etwas loggen. Dafür gibt es $effect.
<script>
let count = $state(0);
// Läuft nach dem Mounten und immer, wenn sich count ändert:
$effect(() => {
document.title = `${count} Klicks`;
});
</script>Ein $effect läuft einmal, nachdem die Komponente gerendert wurde, und danach
erneut, sobald sich eine seiner Abhängigkeiten ändert.
Automatisches Dependency-Tracking
Wie bei $derived musst du Abhängigkeiten nicht angeben. Svelte merkt sich jeden
reaktiven Wert, den du während des Laufs liest, und startet den Effekt genau
dann neu, wenn sich einer davon ändert.
let a = $state(1);
let b = $state(2);
$effect(() => {
// Nur `a` wird gelesen → nur `a` ist Abhängigkeit.
// Ändert sich `b`, läuft dieser Effekt NICHT neu.
console.log('a =', a);
});Effekt-Log (neueste zuerst):
Jeder Tastendruck ändert name — der Effekt läuft automatisch und schreibt eine
neue Zeile.
Aufräumen mit einer Rückgabefunktion
Startet ein Effekt etwas Langlebiges — einen Timer, eine Subscription, einen Event-Listener — muss das wieder abgebaut werden. Dafür gibst du aus dem Effekt eine Cleanup-Funktion zurück. Sie läuft, bevor der Effekt erneut startet, und wenn die Komponente verschwindet.
let laeuft = $state(false);
$effect(() => {
if (!laeuft) return;
const id = setInterval(() => console.log('tick'), 1000);
// Die Rückgabefunktion räumt auf: vor dem nächsten Lauf
// und beim Entfernen der Komponente.
return () => clearInterval(id);
});Startet laeuft auf true, legt der Effekt ein setInterval an. Beim Stoppen räumt die Rückgabefunktion es per clearInterval wieder ab — kein Speicherleck.
Praktische Einsätze
Typische Fälle: einen Wert in localStorage spiegeln, eine externe Bibliothek
synchron halten oder auf DOM-Ereignisse reagieren.
let theme = $state('light');
// Persistiert den Wert automatisch bei jeder Änderung:
$effect(() => {
localStorage.setItem('theme', theme);
});$effect.pre — vor dem DOM-Update
Standardmäßig läuft $effect nach dem DOM-Update. Manchmal brauchst du
den Zustand davor — etwa um die Scroll-Position zu lesen, bevor neue Elemente
gerendert werden. Dafür gibt es $effect.pre, das ansonsten identisch funktioniert.
<script>
let nachrichten = $state([]);
let liste;
// $effect.pre läuft VOR dem DOM-Update — praktisch, um z.B.
// die Scroll-Position zu lesen, bevor neue Einträge gerendert werden.
$effect.pre(() => {
nachrichten.length; // als Abhängigkeit lesen
if (!liste) return;
const amEnde = liste.scrollTop + liste.clientHeight >= liste.scrollHeight;
if (amEnde) queueMicrotask(() => (liste.scrollTop = liste.scrollHeight));
});
</script>Wann du $effect NICHT nutzen solltest
$effect ist mächtig — und wird deshalb gern übernutzt. Der häufigste Fehler:
einen Effekt zu verwenden, um einen State-Wert aus einem anderen zu berechnen. Das ist ein
abgeleiteter Wert und gehört in ein $derived.
let vorname = $state('Anna');
let nachname = $state('Berg');
let vollname = $state('');
// ❌ FALSCH: State aus anderem State per Effekt synchronisieren
$effect(() => {
vollname = `${vorname} ${nachname}`;
});
// ✅ RICHTIG: das ist ein abgeleiteter Wert
let vollname2 = $derived(`${vorname} ${nachname}`);⚠️ Häufige Fehlnutzung: State-Synchronisation
Wenn ein Effekt am Ende nur einen anderen $state setzt, ist es
fast immer ein verkapptes $derived. Die Effekt-Variante ist umständlicher,
fehleranfälliger (Endlosschleifen!) und läuft einen Tick zu spät. Faustregel: Berechnest du einen Wert, nimm $derived. Erst wenn du wirklich mit der Außenwelt sprichst, ist $effect richtig.
Rails-Vergleich
$effect erinnert an ActiveRecord-Callbacks wie after_save: Code, der
als Nebenwirkung läuft, wenn etwas passiert.
🛤️ Rails-Vergleich: Callbacks vs. $effect
Ein after_save-Callback feuert bei einem konkreten Ereignis (dem Speichern). Ein $effect feuert automatisch, sobald sich
irgendeine gelesene Abhängigkeit ändert — du beschreibst nur was passieren soll,
nicht wann. Und wie ein sauber geschriebener Callback räumt ein guter Effekt hinter
sich auf.
class Article < ApplicationRecord
# Läuft als Nebenwirkung nach dem Speichern:
after_save :reindex_search, :notify_subscribers
private
def reindex_search
SearchIndex.update(self) # externer Effekt
end
end
# Der Callback feuert bei einem konkreten Ereignis (save).
# $effect feuert automatisch, wenn sich eine gelesene
# Abhängigkeit ändert — du sagst nur WAS, nicht WANN.Zusammenfassung
💡 Das Wichtigste
$effect(() => { … })läuft nach dem Mounten und bei jeder Änderung einer gelesenen Abhängigkeit.- Abhängigkeiten werden automatisch erkannt.
- Eine Rückgabefunktion räumt auf (Timer, Listener, Subscriptions).
$effect.preläuft vor dem DOM-Update.- Nicht für abgeleitete Werte oder State-Sync nutzen — dafür ist
$derivedda.
🎯 Probier es selbst
Erweitere die Timer-Demo so, dass der Dokumenttitel (document.title) laufend die
verstrichenen Sekunden anzeigt. Nutze dafür einen zweiten $effect, der sekunden liest. Beobachte im Browser-Tab, wie der Titel mitzählt.