Migrating from custom stores to class-based state with runes: idiomatic patterns for deeply nested domain state? #18688
|
I'm migrating a large dashboard (~40 domain stores) from Svelte 4 to Svelte 5. // dashboard.svelte.ts
export class DashboardState {
widgets = $state<Widget[]>([]);
filters = $state<Filters>({ status: 'all', range: null });
visible = $derived(this.widgets.filter(w => matches(w, this.filters)));
setFilter(patch: Partial<Filters>) {
Object.assign(this.filters, patch);
}
}
export const dashboard = new DashboardState();What I've established so far
I've read #10262 ("$state the new store?"), #14338 (deeply nested 2-way Questions
I'm not proposing stores be removed or that runes are "better" — I just want to |
Replies: 1 comment
|
Yes. In Svelte 5, idiomatic domain state is a class in a .svelte.ts file: $state per field, $derived for computed values, private fields with getters for encapsulation. // dashboard.svelte.ts
export class DashboardState {
#widgets = $state<Widget[]>([]);
get widgets() { return this.#widgets; }
visible = $derived(this.#widgets.filter(w => w.active));
setRevenue(id: string, v: number) {
const w = this.#widgets.find(w => w.id === id);
if (w) w.revenue = v; // deep mutation, tracked per-property
}
}Consumers read Rules:
Fine-grained reactivity is automatic: |
Yes. In Svelte 5, idiomatic domain state is a class in a .svelte.ts file: $state per field, $derived for computed values, private fields with getters for encapsulation.
Consumers read
dashboard.visibledirectly — no$prefix, no subscriptions.Rules:
$derivedfor computed values; getters for access only. Getters are reactive but uncached — th…