Stores
Problem
You have several related signals and computed values for a single feature. Keeping them as loose module-level variables makes the boundaries unclear — grouping them into a store object organizes ownership.
Solution
Basic Store
ts
import { store, watch, batch, computed } from '@vielzeug/stateit';
const cart = store({ items: [] as string[], total: 0 });
// Partial patch
cart.patch({ total: 42 });
// Updater function
cart.update((s) => ({ ...s, items: [...s.items, 'apple'] }));
// Watch a derived slice via computed()
const totalSignal = computed(() => cart.value.total);
watch(totalSignal, (total) => console.log('total:', total));
// Batch
batch(() => {
cart.patch({ total: 0 });
cart.update((s) => ({ ...s, items: [] }));
});
cart.reset();Slice Watch via Getter + watch()
ts
import { store, watch } from '@vielzeug/stateit';
const user = store({ id: 1, name: 'Alice', role: 'admin' });
const sub = watch(() => user.value.name, (name, prev) => {
console.log('name:', prev, '→', name);
});
user.patch({ role: 'editor' }); // ← does NOT fire (name unchanged)
user.patch({ name: 'Bob' }); // → "name: Alice → Bob"
sub.dispose();Resetting to Initial State
reset() restores the state passed to store() and protects it from external mutation:
ts
import { store } from '@vielzeug/stateit';
const s = store({ count: 0, label: 'default' });
s.patch({ count: 10, label: 'modified' });
console.log(s.value); // { count: 10, label: 'modified' }
s.reset();
console.log(s.value); // { count: 0, label: 'default' }Pitfalls
- Computed values are recalculated lazily when accessed, not eagerly when dependencies change. Reading a computed in a
setTimeoutmay return a stale value if it has not been accessed since the last signal update. - Exporting a writable store directly allows external code to mutate it and bypass your invariants. Export
readonly(store)and explicit mutation functions instead. - Creating a store inside a factory function called multiple times creates independent instances. This is correct for per-component stores but wrong for shared module stores — create module-level stores outside any function.