# Framework bindings Source: https://selfstore.dev/docs/frameworks React, Svelte and Vue in a few lines each - there is deliberately no adapter package to install. The whole binding contract is two members every store has: `store.subscribe(fn)` and `store.state` (with `store.status` and `store.error` on top). The state snapshot is **referentially stable** between changes, so equality-based frameworks re-render only when something actually changed. That is why there is no `selfstore-react` package: it would be three lines in a trench coat. ## React ```tsx import { useSyncExternalStore } from 'react'; function useStatus() { useSyncExternalStore(store.subscribe, () => store.state, () => store.state); return store.status; // { state, severity, action, labelKey } } function SaveBadge() { const status = useStatus(); return {t(status.labelKey)}; } ``` The **third argument matters**: it is the server snapshot, and without it `useSyncExternalStore` throws during SSR (Next.js, Remix). Keep it. ## Svelte The store contract is structural, so this object **is** a Svelte readable, no `svelte` import needed, Svelte 3 through 5: ```ts export const persistence = { subscribe(run: (s: typeof store.state) => void) { run(store.state); return store.subscribe(() => run(store.state)); }, }; ``` ```svelte {t($persistence.status.labelKey)} ``` ## Vue ```ts import { onMounted, onUnmounted, shallowRef } from 'vue'; export function usePersistence() { const state = shallowRef(store.state); let stop: (() => void) | undefined; onMounted(() => (stop = store.subscribe(() => (state.value = store.state)))); onUnmounted(() => stop?.()); return state; } ``` Solid, Preact signals, Lit, vanilla: same shape. Subscribe on mount, read `store.state`, call the returned unsubscriber on unmount. ## Two gestures, and teardown `store.status.action` is set only when the user must act, and only to one of two values. Offer exactly that gesture: ```ts if (store.status.action === 'unlock') await store.unlock(await promptPassword()); if (store.status.action === 'reconnect') await store.reconnect(); ``` Transient trouble (offline, a cold-started backend, a 5xx) never sets `action`: the edit stays safe locally and the next save or sync retries on its own. In an SPA, call `store.dispose()` when a route-scoped or test-scoped store unmounts: it cancels timers and drops subscribers. An app-wide store needs nothing. Map of this site for a model: https://selfstore.dev/llms.txt Every page in one file: https://selfstore.dev/llms-full.txt