12k
All articles

State Management in Svelte 5 mit Runes

State-Management in Svelte 5 mit Runes: $state, $derived und $effect nutzen, State zwischen Komponenten teilen und SSR-Leaks in SvelteKit vermeiden.

OpenReplay Team
OpenReplay Team
State Management in Svelte 5 mit Runes

Runes sind Compiler-Direktiven — keine Runtime-Imports — die Reaktivität explizit und portabel machen: $state deklariert eine reaktive Zelle, $derived berechnet einen Wert daraus, und $effect reagiert auf Änderungen — und ersetzen gemeinsam Svelte 4’s implizite $:-Deklarationen und Writable Stores in allen drei Rollen. Die Svelte-Dokumentation beschreibt Runes als Schlüsselwörter, die der Compiler erkennt, weshalb sie weder als Alias definiert, importiert noch bedingt aufgerufen werden können. $state in eine einzelne Komponente einzubinden ist der einfache Teil. Der schwierige Teil — der Teil, der in der Produktion Probleme verursacht — ist die Strukturierung von State, den mehrere Komponenten teilen, ohne die Reaktivität zu verlieren, und die korrekte Abgrenzung dieses States, wenn SvelteKit serverseitig rendert.

Dieser Artikel behandelt State Management als eine zusammenhängende Struktur: lokaler State mit $state, berechneter State mit $derived, Seiteneffekte mit $effect, und dann der Teil, den die meisten Anleitungen überspringen — State-Sharing über Dateigrenzen hinweg via .svelte.ts-Module, Request-spezifische Abgrenzung für SSR und eine Entscheidungsregel für die Wahl des richtigen Werkzeugs bei jedem Schritt. Der rote Faden: Reaktivität in Svelte 5 ist wertbasiert opt-in, und nahezu jede Fehlerquelle entsteht dort, wo der Proxy aufhört — Klasseninstanzen, destrukturierte Bindings und ESM-let-Exporte liegen alle außerhalb der Proxy-Grenze. Die hier referenzierten Versionen beziehen sich auf Svelte 5.x und SvelteKit 2.x.

Wichtigste Erkenntnisse

  • Jeder Wert, der als reine Funktion des bestehenden States ausgedrückt werden kann, gehört in $derived, nicht in $effect; die Verwendung von $effect zur Synchronisierung eines State-Werts aus einem anderen ist die häufigste Fehlanwendung der Rune.
  • Der Export eines neu zuweisbaren $state aus einem .svelte.ts-Modul löst den Compile-Fehler state_invalid_export aus; die zwei offiziell unterstützten Lösungen sind der Export einer Funktion, die den State zurückgibt, oder der Export einer const-Objekt- oder Klasseninstanz mit Mutation ihrer Eigenschaften.
  • Das empfohlene Muster für app-weiten Client-State ist eine Klasse mit $state-Feldern, die als const-Instanz exportiert wird — das const-Binding wird nie neu zugewiesen, womit das state_invalid_export-Problem entfällt.
  • Ein .svelte.ts-Modul, das Top-Level-$state deklariert, erstellt eine gemeinsam genutzte Instanz pro Serverprozess, was in SvelteKit SSR zu State-Leaks zwischen Benutzern führt; Request-spezifischer State sollte aus load zurückgegeben und über setContext/getContext geteilt werden.
  • Das Destrukturieren eines $state-Objekts erfasst den Wert zum Zeitpunkt der Destrukturierung, nicht ein reaktives Binding — lesen Sie durch den Proxy oder übergeben Sie einen Getter, um die Reaktivität zu erhalten.

Was ist $state und wie funktioniert lokaler reaktiver State?

$state deklariert eine reaktive Zelle, deren Lesezugriffe Abhängigkeiten registrieren und deren Schreibzugriffe Updates einplanen; bei primitiven Typen wird normal zugewiesen und neu zugewiesen, und bei Objekten und Arrays gibt Svelte einen tiefen Proxy zurück, sodass direkte Mutationen nachverfolgt werden. Gemäß der $state-Dokumentation wird ein einfaches Objekt oder Array durch Übergabe tief reaktiv — es wird direkt mutiert und abhängige UI-Elemente werden aktualisiert.

<script lang="ts">
  let count = $state(0);
  let todos = $state([{ id: 1, text: 'Learn runes', done: false }]);

  function addTodo() {
    todos.push({ id: Date.now(), text: 'New todo', done: false }); // tracked
  }

  function toggle(id: number) {
    const todo = todos.find((t) => t.id === id);
    if (todo) todo.done = !todo.done; // property assignment is tracked
  }
</script>

<button onclick={() => count++}>Clicked {count} times</button>

Bei einem tief reaktiven $state-Objekt oder -Array funktionieren sowohl push() als auch direkte Property-Zuweisung, da der Proxy Mutationen auf jeder Tiefe abfängt. Die Dokumentation weist auf eine Grenze hin: Die Proxifizierung endet bei Klasseninstanzen. Ein einfaches Objekt oder Array wird tief reaktiv; eine Klasseninstanz hingegen nicht, es sei denn, ihre Felder sind selbst mit $state deklariert.

Für große, flache Daten, die komplett ersetzt statt mutiert werden, verwenden Sie $state.raw, das nur Neuzuweisungen — nicht Mutationen — nachverfolgt.

<script lang="ts">
  let payload = $state.raw(largeApiResponse);

  // payload.foo = 'x';  // kein Update — Mutation wird nicht nachverfolgt
  payload = { ...payload, foo: 'x' }; // Update wird ausgelöst — Neuzuweisung wird nachverfolgt
</script>

$state.raw überspringt die Proxy-Erstellung und vermeidet damit den Overhead der Property-Deskriptoren beim tiefen Proxying großer, flacher Objekte. Greifen Sie darauf zurück, wenn Werte groß, praktisch unveränderlich und als Einheit ersetzt werden — geparste JSON-Antworten, Konfigurationsdaten, Lookup-Tabellen. Verwenden Sie ansonsten standardmäßig $state.

Wie verarbeiten $derived und $derived.by berechneten State?

$derived deklariert einen Wert, der aus reaktivem State berechnet wird und sich automatisch aktualisiert, wenn sich seine Abhängigkeiten ändern — als Ersatz für Svelte 4’s reaktive $:-Deklarationen. Gemäß der $derived-Dokumentation wird der Wert aus seinen Abhängigkeiten neu berechnet, wenn er nach einer Änderung das nächste Mal gelesen wird. Seit Svelte 5.25 kann ein nicht-const-Derived auch temporär neu zugewiesen werden, um seinen Wert zu überschreiben — nützlich für optimistische UI — wonach er beim nächsten Ändern einer Abhängigkeit zu seinem berechneten Wert zurückkehrt.

<script lang="ts">
  let count = $state(0);
  let doubled = $derived(count * 2);
  let isEven = $derived(count % 2 === 0);
</script>

Für Berechnungen, die Schleifen, Bedingungen oder mehrere Anweisungen erfordern, verwenden Sie $derived.by, das anstelle eines Ausdrucks eine Funktion entgegennimmt:

<script lang="ts">
  let items = $state([{ price: 10, quantity: 2 }]);

  let summary = $derived.by(() => {
    let total = 0;
    let count = 0;
    for (const item of items) {
      total += item.price * item.quantity;
      count += item.quantity;
    }
    return { total, count };
  });
</script>

Die Regel, die die meisten Reaktivitätsfehler verhindert: Jeder Wert, der als reine Funktion des bestehenden States ausgedrückt werden kann, gehört in $derived, nicht in $effect. Die Verwendung von $effect zur Synchronisierung eines State-Werts aus einem anderen führt zu einem redundanten reaktiven Zyklus und ist die häufigste Fehlanwendung der Rune. Wenn Sie einen Effect schreiben, der State aus anderem State setzt, ersetzen Sie ihn durch $derived.

Wann sollte $effect verwendet werden?

$effect ist ausschließlich für Seiteneffekte gedacht — Subscriptions, Logging, manuelle DOM-Operationen und Persistenz — niemals zur Ableitung von Werten. Gemäß der $effect-Dokumentation laufen Effects nach der DOM-Aktualisierung, verfolgen automatisch die darin gelesenen reaktiven Werte, werden bei deren Änderung erneut ausgeführt und laufen ausschließlich im Browser — niemals während SSR. Es gibt kein Dependency-Array; Svelte erkennt Abhängigkeiten anhand der gelesenen Werte.

<script lang="ts">
  let count = $state(0);

  $effect(() => {
    const id = setInterval(() => console.log('tick', count), 1000);
    return () => clearInterval(id); // Cleanup läuft vor der erneuten Ausführung und beim Zerstören
  });
</script>

Die zurückgegebene Funktion ist ein Cleanup-Callback — sie wird ausgeführt, bevor der Effect erneut läuft und wenn die Komponente zerstört wird; dort werden Intervalle, Listener und Subscriptions abgebaut. Da Effects SSR vollständig überspringen, sollten Sie sich nicht auf sie verlassen, um serverseitig gerendertes Output zu erzeugen; diese Aufgabe gehört in load-Funktionen oder $derived.

Die eine Fehlanwendung, die es sich zu merken lohnt: Verwenden Sie $effect nicht zum Kopieren von State. Das Schreiben von $effect(() => { fullName = `${first} ${last}` }) erzeugt eine Write-Back-Schleife, wo ein $derived sowohl korrekt als auch einfacher wäre:

<script lang="ts">
  let first = $state('Ada');
  let last = $state('Lovelace');
  let fullName = $derived(`${first} ${last}`); // korrekt — kein Effect erforderlich
</script>

Wie teilt man State über Komponenten hinweg in Svelte 5?

Um reaktiven State über Dateien hinweg zu teilen, legen Sie ihn in einem .svelte.ts-Modul ab — allerdings können Sie ein neu zuweisbares $state-Binding nicht direkt exportieren. Das naheliegende Muster schlägt fehl:

// src/lib/counter.svelte.ts
export let count = $state(0);
export function increment() {
  count += 1;
}

Der Export eines neu zuweisbaren $state-Bindings aus einem Modul auf diese Weise löst den dokumentierten state_invalid_export-Compile-Fehler aus, mit der genauen Meldung: “Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value’s properties.” Auslöser ist die Neuzuweisung (count += 1), nicht der Import selbst — der Fehler tritt auf, weil der exportierte $state neu zugewiesen wird, was ein ESM-let-Export nicht sicher über die Modulgrenze hinweg tun kann. Es gibt zwei offiziell unterstützte Lösungen.

Lösung 1 — ein const-Objekt exportieren und seine Eigenschaften mutieren. Das Binding wird nie neu zugewiesen; nur seine Eigenschaften ändern sich, sodass jeder Importeur denselben Proxy liest.

// src/lib/counter.svelte.ts
export const counter = $state({ count: 0 });
export function increment() {
  counter.count += 1; // Property-Mutation, keine Neubindung
}

Lösung 2 — den State dateilokal halten und Getter exportieren. Dadurch bleibt die Zelle privat und externe Neuzuweisungen werden verhindert.

// src/lib/counter.svelte.ts
let count = $state(0);
export function getCount() {
  return count;
}
export function increment() {
  count += 1;
}

Das empfohlene Muster für app-weiten Client-State ist die sauberste Variante von Lösung 1: eine Klasse mit $state-Feldern, die als const-Instanz exportiert wird. Das const-Binding wird nie neu zugewiesen, womit das state_invalid_export-Problem entfällt, und jede Komponente, die die Instanz importiert, liest aus demselben reaktiven Proxy.

// src/lib/todo-store.svelte.ts
class Todo {
  done = $state(false);
  text = $state('');
  constructor(text: string) {
    this.text = text;
  }
}

class TodoStore {
  items = $state<Todo[]>([]);
  filter = $state<'all' | 'active' | 'done'>('all');

  get visible(): Todo[] {
    if (this.filter === 'all') return this.items;
    const wantDone = this.filter === 'done';
    return this.items.filter((t) => t.done === wantDone);
  }

  add(text: string) {
    this.items.push(new Todo(text));
  }

  remove(todo: Todo) {
    this.items = this.items.filter((t) => t !== todo);
  }
}

export const todoStore = new TodoStore();

Jede Komponente, die todoStore importiert, liest und mutiert dieselbe reaktive Instanz — ohne Context-Verkabelung, ohne Subscription-Boilerplate. Beachten Sie den $state<Todo[]>([])-Typparameter: TypeScript leitet Typen aus Initialwerten ab, aber bei leeren Arrays, leeren Objekten oder Unions, die breiter als der Initialwert sind, übergeben Sie einen expliziten Parameter. Dieses Muster hat einen wichtigen Vorbehalt für SSR, der weiter unten behandelt wird.

Wie verhält sich $state innerhalb von Klassen?

$state funktioniert als Klassenfeld, und der Compiler transformiert jedes Feld in ein Prototyp-Get/Set-Accessor-Paar, das durch ein privates Signal unterstützt wird. Die $state-Klassen-Dokumentation beschreibt diese Transformation, und sie hat zwei erwähnenswerte Konsequenzen: Da die Accessors auf dem Prototyp statt auf der Instanz liegen, listet Object.keys(instance) keine reaktiven Felder auf, und das Spreaden mit { ...instance } lässt sie aus.

class Todo {
  done = $state(false);
  text = $state('');
  constructor(text: string) {
    this.text = text;
  }
  toggle() {
    this.done = !this.done;
  }
}

Die Falle, in die jeder tappt, ist die this-Bindung in Event-Handlern. Die Übergabe einer Methodenreferenz löst sie von der Instanz, und die Dokumentation behandelt diesen Fall direkt:

<!-- this === der <button>, nicht die Todo-Instanz — fehlerhaft -->
<button onclick={todo.toggle}>toggle</button>

<!-- this === todo — funktioniert -->
<button onclick={() => todo.toggle()}>toggle</button>

Da Lese- und Schreibzugriffe über Prototyp-Accessors laufen, benötigt die Methode das korrekte this. Zwei Lösungen halten es gebunden: die Aufrufstelle in eine Arrow-Funktion einwickeln (() => todo.toggle()), oder die Methode als Arrow-Funktionsfeld definieren, sodass sie über this schließt:

class Todo {
  done = $state(false);
  toggle = () => {
    this.done = !this.done; // Arrow-Feld — `this` ist dauerhaft gebunden
  };
}

Verwenden Sie die Arrow-Feld-Form, wenn Sie die Methode als Referenz weitergeben möchten; verwenden Sie eine normale Methode, wenn Sie sie stets als todo.toggle() aufrufen.

Was sind die wichtigsten Reaktivitätsfallen bei Runes?

Die meisten Runes-Fehler lassen sich auf eine einzige Regel zurückführen: Reaktivität ist wertbasiert opt-in, und der Proxy endet bei Klasseninstanzen, destrukturierten Bindings und ESM-Exporten. Drei Fallen sind für die Mehrheit der verlorenen Reaktivität verantwortlich.

Destrukturierung erfasst einen Wert, kein Binding. Das Destrukturieren eines $state-Objekts liest den Wert zum Zeitpunkt der Destrukturierung; es erstellt keine reaktive Referenz.

const user = $state({ name: 'Ada', age: 36 });
const { name } = user;
user.name = 'Grace'; // user.name wird aktualisiert
console.log(name); // immer noch 'Ada' — zum Zeitpunkt der Destrukturierung erfasst

Um die Reaktivität zu erhalten, lesen Sie durch den ursprünglichen Proxy (user.name) oder übergeben Sie eine Getter-Funktion (() => user.name), die über den Proxy schließt und bei jedem Aufruf neu liest. Das ist die Lösung, die immer dann greift, wenn ein Wert „aufhört sich zu aktualisieren”, nachdem er in eine Variable umstrukturiert wurde.

Native Map, Set, Date und URL sind Klasseninstanzen, daher endet der Proxy bei ihnen. Verwenden Sie die reaktiven Äquivalente aus svelte/reactivity, die Lesezugriffe auf .size, .get(), .has() und Iteration nachverfolgen: SvelteMap, SvelteSet, SvelteDate, SvelteURL und SvelteURLSearchParams.

import { SvelteMap } from 'svelte/reactivity';

const cache = new SvelteMap<string, number>();
cache.set('a', 1); // reaktiv

Die Dokumentation weist auf einen Vorbehalt hin: Werte, die innerhalb einer reaktiven Map oder Set gespeichert sind, werden nicht tief reaktiv gemacht. Wenn Sie ein einfaches Objekt in einer SvelteMap speichern und erwarten, es reaktiv zu mutieren, umhüllen Sie dieses Objekt zuerst mit $state.

Proxies können bestimmte API-Grenzen nicht überschreiten. structuredClone, postMessage und einige Serialisierer lehnen Proxies ab. Verwenden Sie $state.snapshot, um an der Grenze eine einfache, statische Kopie zu erstellen:

await fetch('/api/save', {
  method: 'POST',
  body: JSON.stringify($state.snapshot(user)),
});

Verwenden Sie $state.snapshot nur an diesen Grenzen, nicht im gesamten Code — der Proxy ist das, was Sie überall sonst benötigen.

Wann sollte modularer globaler State versus Svelte Context verwendet werden?

Modularer globaler State ist für reine Client-Anwendungen sicher, aber unsicher für SSR; Request-spezifischer State gehört in eine load-Funktion und wird über Svelte’s Context-API geteilt. Ein .svelte.ts-Modul, das $state auf oberster Ebene deklariert, erstellt eine einzige gemeinsam genutzte Instanz pro Serverprozess. Auf dem Client ist das genau das Gewünschte. In SvelteKit SSR ist es ein Request-Leak-Risiko: Die SvelteKit State-Management-Dokumentation stellt fest, dass Server langlebig und über Benutzer hinweg geteilt sind, dass benutzerspezifische Daten nicht in gemeinsam genutzten Modulvariablen gespeichert werden dürfen, und gibt das kanonische Beispiel, bei dem das Geheimnis eines Benutzers in das Rendering eines anderen durchsickert.

Der Leak sieht folgendermaßen aus — ein Modul-Store, der während eines Server-Renderings mutiert wird, ist für den nächsten Request sichtbar, der denselben Prozess trifft:

// src/lib/user.svelte.ts — GEFÄHRLICH in SSR
export const currentUser = $state({ name: '' });
// +page.server.ts — setzt gemeinsamen State während SSR
import { currentUser } from '$lib/user.svelte';

export function load({ locals }) {
  currentUser.name = locals.user.name; // Leak über Requests hinweg
}

Die kanonische Lösung besteht darin, Request-spezifische Daten aus load zurückzugeben und sie über setContext/getContext zu teilen, was den Wert auf einen einzelnen Komponentenbaum — und damit einen einzelnen Request — statt auf ein prozessweites Modul beschränkt.

// +layout.server.ts
export function load({ locals }) {
  return { user: locals.user }; // Request-spezifische Daten
}
<!-- +layout.svelte -->
<script lang="ts">
  import { setContext } from 'svelte';
  let { data } = $props();
  setContext('user', data.user); // auf den Komponentenbaum dieses Requests beschränkt
</script>

In produktiven SvelteKit-Anwendungen zeigt sich falsch abgegrenzter State auf Modulebene in Session-Replays daran, dass ein Benutzer kurzzeitig die Daten eines anderen Benutzers oder veraltete Werte beim initialen Laden sieht — das sichtbare Symptom von State, der durch Rückgabe Request-spezifischer Daten aus load und Weitergabe über Context hätte abgegrenzt werden sollen, statt in einem modularen Global gehalten zu werden. Session-Replays dieser Implementierungen machen den Fehler sichtbar, da sie das initial server-gerenderte DOM erfassen, nicht nur den Post-Hydration-State.

Die Entscheidungsregel, die die gesamte Struktur zusammenfasst:

Verwenden Sie komponentenlokalen $state für Werte, die einer Komponente gehören; $derived für alles, was aus diesem State berechnet wird; einen modularen Klassen-Store (export const store = new Store()) für app-weiten Client-State; und Request-spezifische Daten, die aus load zurückgegeben und über setContext/getContext geteilt werden, für Request-spezifischen oder SSR-State, der nicht zwischen Benutzern durchsickern darf.

Props-Verkabelung — $props, $bindable und das $inspect-Debug-Hilfsmittel — liegt außerhalb dieser State-Management-Struktur; behandeln Sie sie als Komponenten-Interface- und Debugging-Werkzeuge, nicht als State-Container.

Migration von Svelte 4 Stores zu Runes

Die meisten Svelte 4-Reaktivitätsmuster lassen sich direkt auf Runes übertragen, einschließlich des Shared-State-Falls, der früher Writable Stores gehörte. Die folgende Tabelle deckt die Übersetzungen ab, auf die Entwickler mit mittleren Kenntnissen am häufigsten stoßen; der Svelte 5 Migrationsleitfaden deckt die gesamte Oberfläche ab.

Svelte 4Svelte 5 Runes
let count = 0;let count = $state(0);
$: doubled = count * 2;let doubled = $derived(count * 2);
$: console.log(count);$effect(() => console.log(count));
export let name = 'world';let { name = 'world' } = $props();
const count = writable(0); $count++let count = $state(0); count++
writable Store, komponentenübergreifend geteiltKlassen-Store, exportiert als export const store = new Store()
Store, in SSR-Layout für benutzerspezifische Daten abonniertload gibt Daten zurück → setContext/getContext

Die letzten beiden Zeilen sind diejenigen, die die meisten Anleitungen auslassen: Ein Writable Store, der app-weit geteilt wird, wird zu einer Klasseninstanz, die als const exportiert wird, und ein benutzerspezifischer Store in einem SSR-Kontext wird zu Request-spezifischen Daten, die aus load zurückgegeben und über Context weitergegeben werden.

Runes machen das Reaktivitätsmodell explizit, aber der eigentliche Vorteil liegt in der Architektur: State so lokal wie möglich halten, ihn nur dann zu einem modularen Klassen-Store hochstufen, wenn mehrere Komponenten ihn tatsächlich teilen, und ihn über Context abgrenzen, sobald SSR ins Spiel kommt. Prüfen Sie Ihre .svelte.ts-Module auf Top-Level-$state, der am Server-Rendering beteiligt ist — diese einzelne Überprüfung deckt die schwerwiegendste Klasse von State-Fehlern in SvelteKit auf.

FAQs

Was ist der Unterschied zwischen $state.raw und $state in Svelte 5?

$state gibt einen tiefen Proxy zurück, der Mutationen auf jeder Tiefe nachverfolgt, sodass push() und Property-Zuweisung Updates auslösen; $state.raw überspringt die Proxy-Erstellung und verfolgt nur Neuzuweisungen — direkte Mutationen werden ignoriert, und der Wert muss komplett ersetzt werden, um ein Update auszulösen. Verwenden Sie $state.raw für große, praktisch unveränderliche Daten, die als Einheit ersetzt werden, wie geparste JSON-Antworten, Konfigurationsdaten oder Lookup-Tabellen, bei denen das Überspringen des Property-Proxy-Overheads relevant ist. Verwenden Sie ansonsten standardmäßig $state.

Warum hört mein $state-Wert auf sich zu aktualisieren, nachdem ich ihn destrukturiert habe?

Das Destrukturieren eines $state-Objekts liest den Wert zum Zeitpunkt der Destrukturierung und erstellt eine einfache, nicht-reaktive Variable; es erstellt kein reaktives Binding zum Proxy. Nach const name = user.name aktualisiert eine spätere Mutation von user.name den Proxy, lässt aber das destrukturierte name bei seinem ursprünglichen Wert eingefroren. Um die Reaktivität zu erhalten, lesen Sie durch den ursprünglichen Proxy mit user.name an der Verwendungsstelle, oder übergeben Sie eine Getter-Funktion wie () => user.name, die über den Proxy schließt und bei jedem Aufruf neu liest.

Werden $effect-Callbacks während SSR in SvelteKit ausgeführt?

Nein. $effect-Callbacks laufen ausschließlich im Browser und niemals während des serverseitigen Renderings. Effects laufen nach der DOM-Aktualisierung und werden erneut ausgeführt, wenn sich die darin gelesenen reaktiven Werte ändern — das bedeutet, sie können nicht zum server-gerenderten HTML beitragen. Verlassen Sie sich nicht auf $effect, um Output während SSR zu erzeugen; platzieren Sie diese Arbeit in einer load-Funktion oder in $derived. Effects sind für ausschließlich browserseitige Seiteneffekte wie Subscriptions, Logging, manuelle DOM-Operationen, Intervalle und Persistenz gedacht, mit einem optionalen zurückgegebenen Cleanup-Callback.

Sind Werte, die in einer SvelteMap oder SvelteSet gespeichert sind, tief reaktiv?

Nein. SvelteMap und SvelteSet aus svelte/reactivity verfolgen Lesezugriffe auf .size, .get(), .has() und Iteration und reagieren auf das Hinzufügen oder Entfernen von Einträgen, aber die darin gespeicherten Werte werden nicht tief reaktiv gemacht. Wenn Sie ein einfaches Objekt in einer SvelteMap speichern und erwarten, dass das Mutieren seiner Eigenschaften Updates auslöst, umhüllen Sie dieses Objekt zuerst mit $state, damit das innere Objekt zu einem reaktiven Proxy wird. Die reaktive Collection verfolgt die Struktur, nicht den internen State beliebig gespeicherter Werte.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.