$derived — abgeleitete Werte
Werte, die sich aus anderem State ergeben: einmal deklariert, immer aktuell — Svelte berechnet sie automatisch neu, wenn sich eine Abhängigkeit ändert.
Wozu abgeleiteter Zustand?
Oft ergibt sich ein Wert direkt aus einem anderen: der doppelte Zähler, der Gesamtpreis eines
Warenkorbs, ob ein Formular gültig ist. Solche Werte willst du nicht selbst pflegen — $derived übernimmt das. Du beschreibst nur wie sich der Wert berechnet,
und Svelte hält ihn automatisch aktuell.
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
{count} verdoppelt ist {doubled}
</button>doubled wird nie von Hand gesetzt. Ändert sich count, berechnet Svelte doubled neu — und aktualisiert jede Stelle im Markup, die es verwendet.
Automatisches Dependency-Tracking
Das Besondere: Du musst nirgends angeben, wovon ein abgeleiteter Wert abhängt.
Svelte liest den Ausdruck aus und merkt sich automatisch jeden $state, der darin
gelesen wird. Wird eine dieser Quellen geändert, wird neu berechnet — sonst nicht.
let count = $state(0);
// Jeder abgeleitete Wert deklariert seine Abhängigkeit einfach dadurch,
// dass er sie im Ausdruck liest — kein manuelles Verdrahten:
let doubled = $derived(count * 2);
let isEven = $derived(count % 2 === 0);
let label = $derived(isEven ? 'gerade' : 'ungerade');Abgeleitete Werte dürfen sich auch aufeinander stützen: label hängt von isEven ab, das wiederum von count. Svelte löst diese Kette in der
richtigen Reihenfolge auf.
Live ausprobieren
Der folgende Zähler nutzt einen $state und zwei $derived-Werte:
Nur count wird geklickt — doubled und isEven folgen
von allein.
$derived.by für mehr Logik
$derived(ausdruck) erwartet einen einzelnen Ausdruck. Sobald du mehrere Zeilen,
Zwischenschritte oder eine Schleife brauchst, nimmst du $derived.by(() => { … }) — eine Funktion, deren Rückgabewert der abgeleitete Wert ist. Das Dependency-Tracking
funktioniert genauso automatisch.
let zahlen = $state([10, 20, 30]);
// Für mehrzeilige Logik: $derived.by mit einer Funktion.
let statistik = $derived.by(() => {
const summe = zahlen.reduce((a, b) => a + b, 0);
const schnitt = zahlen.length ? summe / zahlen.length : 0;
return { summe, schnitt };
});Warum nicht einfach eine Funktion?
Man könnte den abgeleiteten Wert auch als Funktion schreiben und im Markup aufrufen. Das
funktioniert — ist aber schlechter. Eine Funktion rechnet bei jedem Render
erneut, auch wenn sich nichts Relevantes geändert hat. Ein $derived ist gecacht: Es merkt sich das Ergebnis und berechnet nur dann neu, wenn sich eine
Abhängigkeit tatsächlich ändert.
<script>
let count = $state(0);
// ❌ Funktion: läuft bei JEDEM Render erneut, kein Caching
function doubledFn() {
return count * 2;
}
// ✅ $derived: gecacht, läuft nur neu, wenn count sich ändert
let doubled = $derived(count * 2);
</script>
<p>{doubledFn()}</p> <!-- rechnet jedes Mal -->
<p>{doubled}</p> <!-- liest nur den Cache -->💡 Faustregel
Hängt ein Wert von reaktivem State ab und wird im Markup angezeigt? Dann nimm $derived statt einer Funktion. Das ist ausdrucksstärker und schneller.
Ein $derived darf man nicht zuweisen
Ein abgeleiteter Wert gehört Svelte — er ergibt sich vollständig aus seinen Quellen. Deshalb darfst du ihm nicht direkt einen Wert zuweisen. Willst du das Ergebnis ändern, änderst du die zugrunde liegende Quelle.
let count = $state(0);
let doubled = $derived(count * 2);
doubled = 99; // ❌ Fehler: einem $derived darf man nicht zuweisen
count = 49; // ✅ so beeinflusst man doubled — über die Quelle⚠️ Kein Setter
Eine Zuweisung an ein $derived ist ein Fehler. Denk an einen abgeleiteten Wert
wie an eine Formel in einer Tabellenkalkulation: Du änderst die Eingabezellen, nicht das
Ergebnisfeld.
Rails-Vergleich
In Rails erreichst du Ähnliches mit Memoization (@x ||= …): Ein
Wert wird einmal berechnet und gecacht. Der Unterschied liegt in der Invalidierung.
🛤️ Rails-Vergleich: Memoization vs. $derived
Rails-Memoization cacht, aber invalidiert nie von allein — ändert sich eine
Eingabe, bleibt der Cache veraltet, bis du ihn manuell zurücksetzt. $derived verfolgt seine Abhängigkeiten automatisch und berechnet exakt dann neu, wenn nötig.
class Invoice < ApplicationRecord
# Memoization: berechnet EINMAL, dann gecacht in @total
def total
@total ||= line_items.sum(&:amount)
end
end
# Problem: Ändert sich ein line_item, ist @total veraltet.
# Der Cache invalidiert NICHT von allein — du musst @total = nil
# selbst zurücksetzen. Genau das nimmt dir $derived ab.Zusammenfassung
💡 Das Wichtigste
$derived(ausdruck)deklariert einen Wert, der aus anderem State folgt.$derived.by(() => { … })für mehrzeilige Logik.- Abhängigkeiten werden automatisch erkannt — kein manuelles Verdrahten.
- Das Ergebnis ist gecacht und aktualisiert sich nur bei Bedarf.
- Einem
$deriveddarf man nicht zuweisen — ändere die Quelle.
🎯 Probier es selbst
Ergänze die Statistik-Demo um einen weiteren $derived-Wert maximum,
der die größte Zahl der Liste anzeigt (Tipp: Math.max(...zahlen)). Beobachte,
dass er sich ohne weiteres Zutun aktualisiert, sobald du eine Zahl hinzufügst.