--- title: Lifecycle and persistence description: Coordinate SSR, asynchronous persistence, browser synchronization, and external input validation. order: 20 toc: - id: server-snapshots title: Server snapshots - id: persist-updates title: Persist updates - id: preference-effects title: Preference effects - id: validate-updates title: Validate updates --- ## Server snapshots {#server-snapshots} `initialPreferences` is captured when the provider creates its store. It remains the server and hydration snapshot; changing that prop later does not reset local preferences. Remount the provider when the application intentionally switches to a different preference identity. ## Persist updates {#persist-updates} `onPreferenceChange` runs only when a value actually changes. It may return a promise, but local updates are not blocked while persistence completes. Handle retries, errors, and rollback behavior in the application boundary. ## Preference effects {#preference-effects} Effects connect preferences to APIs outside React: ```tsx const documentEffects = [ { layoutEffect: ({ preferences }) => { document.documentElement.dataset.theme = preferences["theme-mode"] }, effect: ({ store }) => { const media = window.matchMedia("(prefers-color-scheme: dark)") const listener = () => synchronizeTheme(store.getSnapshot(), media) media.addEventListener("change", listener) return () => media.removeEventListener("change", listener) }, }, ] satisfies readonly PreferenceEffect[] ``` Use `layoutEffect` for DOM changes that must happen before paint. Use `effect` for subscriptions. Keep the effects array reference stable because callbacks and cleanup functions run again whenever the snapshot or array changes. ## Validate updates {#validate-updates} Create a type guard from the same definitions before accepting data from an untyped boundary: ```ts const isPreferenceUpdate = createPreferenceUpdateGuard(definitions) if (isPreferenceUpdate(payload)) { await savePreference(payload) } ```