Svelte's Take on ObservableObject
SwiftUI's ObservableObject and @Published make it easy to group related properties into a single class, and to react to changes of individual properties.
I recently complained to my friend, Bobi, that Svelte seemed lacking in this regard. Its tutorials always show components whose exportable state is defined by separate, top-level variable declarations.
let count = 0; $: if (count >= 10) { alert('count is dangerously high!'); ...
She set me straight: if you want to group related, observable properties, just use a writable store whose value is an Object (or if you prefer, a class instance). Whenever any property is changed, interested parties react automatically.
Here's an example, built from a skeleton project configured to use TypeScript.
Create the Project
$ npm create svelte@latest example
This project will use TypeScript.
✔ Which Svelte app template? › Skeleton project
✔ Add type checking with TypeScript? › Yes, using TypeScript syntax
✔ Add ESLint for code linting? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
✔ Add Playwright for browser testing? … No / Yes
✔ Add Vitest for unit testing? … No / Yes
Add a Store
Add a file, src/lib/field_store.ts
:
import { writable } from "svelte/store" class FieldStore { fullname: string = "" age: number | null = null } export const fields = writable(new FieldStore())
Bind to Store Members
Modify src/routes/+page.svelte
to use the store. (Please pardon my dangerous use of unsanitized input values.)
<script lang="ts"> import { fields } from '$lib/field_store' const dfltDispName = '<span class="unknown">I am Spartacus</span>' let dispName = dfltDispName $: dispName = $fields.fullname || dfltDispName const dfltDispAge = '<span class="unknown">not known</span>' let dispAge = dfltDispAge $: dispAge = $fields.age == null ? dfltDispAge : $fields.age.toString() </script> <form> <input type="text" placeholder="Full name" bind:value={$fields.fullname} /> <input type="number" min={0} max={4096} bind:value={$fields.age} /> </form> <p>Full name: {@html dispName}.</p> <p>Age (years): {@html dispAge}.</p> <style> ... </style>
Profit
Summary
That's it! As usual for Svelte, the syntax is beautifully concise.