Der {#key}-Block ist ein Spezial-Konstrukt: Er zerstört und remounted seinen Inhalt jedes Mal, wenn der angegebene Schlüssel-Wert sich ändert. Damit lassen sich Komponenten zurücksetzen, Animationen bei jedem Wechsel auslösen und onMount-Hooks erneut feuern. Dieser Artikel zeigt typische Anwendungsfälle und die Abgrenzung zu anderen Patterns.
Grundsyntax
<script>
let userId = $state(1);
</script>
<select bind:value={userId}>
<option value={1}>User 1</option>
<option value={2}>User 2</option>
</select>
{#key userId}
<UserProfile {userId} />
{/key}Bei jedem Wechsel von userId wird UserProfile komplett zerstört und neu gemountet. State, Refs und Lifecycle-Hooks werden zurückgesetzt.
Wann ist das nötig?
Normalerweise reagiert Svelte auf geänderte Props ohne Neumount: Werte aktualisieren sich, lokaler State bleibt erhalten. In folgenden Fällen will man bewusst alles zurücksetzen:
- Form-Reset bei Wechsel des bearbeiteten Datensatzes.
- Animationen bei jedem Wechsel neu auslösen (Transitions feuern beim Mount).
onMount-Hooks bei jedem Wechsel erneut laufen lassen.- Drittanbieter-Bibliotheken, die nicht mit dynamisch wechselnden Props umgehen können (z. B. einige Chart-Libraries, Map-Komponenten).
Animation bei jedem Wechsel
<script>
import { fade } from 'svelte/transition';
let message = $state('Hallo');
</script>
<input bind:value={message} />
{#key message}
<p in:fade={{ duration: 200 }}>{message}</p>
{/key}Bei jeder Änderung des Texts faded der alte aus, der neue ein — weil Svelte den <p>-Knoten unmounted und neu mountet.
Form-Reset
<script>
let editingId = $state(null);
function startEdit(id) {
editingId = id;
}
</script>
{#key editingId}
<EditForm id={editingId} />
{/key}Wechselt editingId, bekommt EditForm einen frischen Mount. Lokaler Form-State ($state-Variablen, Validierungs-Fehler) wird verworfen und neu initialisiert.
Mehrere Werte als Key
Der Schlüssel kann ein beliebiger Ausdruck sein — bei mehreren Abhängigkeiten z. B. ein zusammengesetzter String:
{#key `${userId}-${role}`}
<Permissions {userId} {role} />
{/key}Sobald sich entweder userId oder role ändert, ändert sich der String — und der Block remounted.
Abgrenzung: {#key} vs. {#if}-Toggle
Beide Patterns zerstören und mounten neu — aber mit unterschiedlicher Semantik:
{#if}-Toggle: „Ist die Komponente sichtbar oder nicht?”{#key}: „Bekommt die Komponente eine neue Identität?”
{#key user.id}
<UserProfile {user} />
{/key}Hier ist UserProfile immer sichtbar — aber bei jedem User-Wechsel komplett neu.
Performance-Aspekt
Ein {#key}-Block ist nicht „kostenlos”: Bei jedem Wechsel werden alle DOM-Knoten innerhalb verworfen und neu erzeugt. Bei großen Subtrees kann das spürbar sein. Verwendung gezielt — nicht als Standard-Pattern.
Wenn nur ein einzelner Effect bei einer Wertänderung neu laufen soll, ist $effect mit der entsprechenden Abhängigkeit oft die bessere Wahl:
<script>
let { userId } = $props();
let user = $state(null);
$effect(() => {
fetch(`/api/users/${userId}`)
.then((r) => r.json())
.then((u) => user = u);
});
</script>
{#if user}
<h1>{user.name}</h1>
{/if}{#key} ist die richtige Wahl, wenn die Komponenten-Identität wechseln soll — nicht nur die Daten darin.
Häufige Stolperfallen
{#key} mit konstantem Schlüssel.
Macht keinen Sinn — der Block bleibt unverändert. Wenn der Schlüssel wirklich konstant ist, kann der Block weg.
{#key} als Ersatz für reaktive Updates.
Wer in jedem Render alles neu mountet, verliert die Vorteile von Svelte’s feinkörnigen Updates. Nur einsetzen, wenn nötig.
Vergessenes {/key}.
Wie bei allen Svelte-Blöcken Pflicht.
Animation tut sich nicht.
<p in:fade>{message}</p>Bei reaktiven Updates des Texts mountet der <p>-Knoten nicht neu — die in:fade läuft nur beim ersten Mount. Mit {#key message} umschließen, damit beim Wechsel neue Animationen feuern.