# useParameterPersistence URL: /docs/native/hooks/use-parameter-persistence Persist a serializable view-parameter snapshot (search, filters, sort, column layout, …) per saved view and restore it on the next mount, backed by a synchronous native key-value store. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/rn-hooks-use-parameter-persistence ``` The module exports the `useParameterPersistence` hook and the helpers the Docyrus listing hooks share: `resolvePersistConfig`, `buildPersistKey`, `getPersistStore`, plus the `PersistStateProp` types. It is the engine behind the `persistState` option of the Docyrus listing hooks. ## Overview The hook takes a snapshot object, restores a stored copy once per storage key, and writes changes back after a debounce. - **Restore once per key.** When `storageKey` changes (for example the user switches to another saved view), the stored overlay for the new key is restored. - **No write before restore.** The first snapshot for a key never overwrites stored state before that key has been restored. - **Ordering.** Declare the hook **after** any effect that applies a saved view, so the restored overlay lands on top of the view preset in the same commit. - **Failure tolerant.** Corrupt JSON, a failing store or a serialization error is ignored. ## Storage on React Native React Native has no `localStorage` / `sessionStorage`, so storage resolves through the package's `lib/storage` module: | Mode | Backend | |------|---------| | `'session'` (default) | In-memory `Map` that lives as long as the JS runtime (until the app is killed or reloaded). | | `'local'` | The store you register with `; } ``` `lib/storage` also exports `setDocyLocalStore(store | null)` (register outside React), `getDocyStore(kind)`, `getInjectedDocyLocalStore()` and `createMemoryStore()`. ## Usage ```tsx import { useCallback, useMemo, useState } from 'react'; import { buildPersistKey, resolvePersistConfig, useParameterPersistence, type PersistStateProp } from '@/hooks/docyrus-native/use-parameter-persistence'; type ListParams = { search: string; sort: string }; export function useContactListParams(viewId: string | null, persistState?: PersistStateProp) { const [search, setSearch] = useState(''); const [sort, setSort] = useState('name'); const config = resolvePersistConfig(persistState); const storageKey = config && viewId ? buildPersistKey(['crm', config.key || 'contacts', viewId]) : null; const snapshot = useMemo(() => ({ search, sort }), [search, sort]); const onRestore = useCallback((restored: Partial) => { if (restored.search !== undefined) setSearch(restored.search); if (restored.sort !== undefined) setSort(restored.sort); }, []); useParameterPersistence({ enabled: Boolean(config), storage: config?.storage ?? 'session', storageKey, ready: viewId !== null, snapshot, onRestore }); return { search, setSearch, sort, setSort }; } ``` ## API Reference ### `useParameterPersistence(args)` Returns `void`. | Argument | Type | Default | Description | |----------|------|---------|-------------| | `enabled` | `boolean` | — | Whether persistence is active at all. | | `storage` | `ParameterPersistenceStorage` | — | `'session'` or `'local'`. | | `storageKey` | `string \| null` | — | Full storage key including the active view id. `null` suspends restore and write until it resolves. | | `ready` | `boolean` | — | Defers restore and write until the surrounding view layer has settled (fields loaded, saved view applied). | | `snapshot` | `T extends object` | — | Current serializable parameter snapshot. Memoize it; it is serialized with `JSON.stringify` on change. | | `onRestore` | `(restored: Partial) => void` | — | Applies a stored snapshot back into state. Read through a ref, so an inline function is fine. | | `debounceMs` | `number` | `300` | Debounce for writes. | ### `resolvePersistConfig(prop)` | Parameter | Type | Description | |-----------|------|-------------| | `prop` | `PersistStateProp \| undefined` | The public `persistState` option. | **Returns:** `{ storage: ParameterPersistenceStorage; key: string } | null`. `true` becomes `{ storage: 'session', key: '' }`; an object fills `storage` (default `'session'`) and `key` (default `''`); falsy returns `null`. ### `buildPersistKey(parts)` | Parameter | Type | Description | |-----------|------|-------------| | `parts` | `ReadonlyArray` | Key segments. Falsy parts are dropped. | **Returns:** `string`, e.g. `docyrus:view-params:::`. ### `getPersistStore(storage)` | Parameter | Type | Description | |-----------|------|-------------| | `storage` | `ParameterPersistenceStorage` | `'session'` or `'local'`. | **Returns:** `DocyKeyValueStore | null`. On native a store is always resolved (see the storage table); `null` only if resolving throws. Shared with the saved-view hooks so every layer resolves storage the same way. ## Type Exports | Type | Description | |------|-------------| | `ParameterPersistenceStorage` | `'session' \| 'local'`. | | `ParameterPersistenceConfig` | `{ storage?: ParameterPersistenceStorage; key?: string }`. `key` overrides the data-source segment so two listings of the same data source don't share state. | | `PersistStateProp` | `boolean \| ParameterPersistenceConfig`. `true` is shorthand for `{ storage: 'session' }`. |