useCreateStorage (memory)
TL;DR. useCreateStorage({ type: 'memory', name, initialState }) — a React hook that
creates a storage right inside a component and destroys it on unmount. The store's lifecycle =
the component's lifecycle; there's no need to keep the store at the module level and manually call
initialize()/destroy().
This is the memory variant (ephemeral, in-memory). The same hook with a different type gives
persistence: localStorage and indexedDB.
The same end-to-end todo domain (TodoState, initialTodoState — see MemoryStorage).
Why
A plain MemoryStorage lives at the module level — one instance for the
whole application, surviving any remounts. But sometimes a store is needed only inside a specific
screen and should disappear together with it (so you don't accumulate the state of closed
components and don't share it between instances). Doing this by hand — holding the store in
useState, calling initialize() in useEffect, destroy() in cleanup, watching out for the
StrictMode double-effect — is noisy and easy to get wrong. useCreateStorage encapsulates this
entire lifecycle.
When to use
The store is needed only inside a component/screen and should disappear together with it.
You don't want manual
initialize()/destroy()inuseEffect.You need several independent instances of the same store (one per mounted component).
When NOT to use
The store must be global and survive unmount → create it at the module level (MemoryStorage) or via createSynapse.
You need selectors / dispatcher / effects (a full-fledged module) → that's createSynapse
createSynapseCtx or awaitSynapse, not a bare storage hook.
The state must survive a reload → the localStorage / indexedDB variant.
Usage
Copy-paste minimal form:
import { useCreateStorage, useStorageSubscribe } from 'synapse-storage/react'
function TodoApp() {
const { storage, isReady, isLoading, hasError, status } = useCreateStorage<TodoState>({
type: 'memory',
name: 'todo-hook-memory',
initialState: initialTodoState,
})
// storage: ISyncStorage<TodoState> | null (non-null only when isReady)
if (isLoading) return <div>Loading…</div>
if (hasError) return <div>Error: {status.error?.message}</div>
if (!isReady) return <div>Initializing…</div>
// After isReady the storage is guaranteed to be non-null
storage.set('filter', 'active')
}Reading state — useStorageSubscribe
// Subscribe to the whole state or to individual fields (re-renders only when the result changes)
const state = useStorageSubscribe(storage, (s) => s)
const filter = useStorageSubscribe(storage, (s) => s.filter)
const activeCount = useStorageSubscribe(storage, (s) => s.todos.filter((t) => !t.done).length)useStorageSubscribe accepts storage | null, so you can call it before readiness — it returns
undefined. More details in Subscriptions.
All parameters (commented)
The whole surface of the hook at once — the config (argument 1) and the lifecycle options (argument 2):
const result = useCreateStorage<TodoState>(
// ── Argument 1: storage config (UniversalStorageConfig) ──────────────────
{
type: 'memory', // 'memory' | 'localStorage' | 'indexedDB' — the type selects the hook variant
name: 'todo-hook-memory', // unique storage name
initialState: initialTodoState, // initial state; TState is inferred from it
// version / migrate — persist migrations; for 'memory' they are ignored (nothing to persist).
// middlewares — the store's middleware configurator (see Middlewares).
},
// ── Argument 2: lifecycle options (optional) ─────────────────────
{
autoInitialize: true, // auto-initialize() on mount. Defaults to true.
// false → initialize manually by calling result.initialize().
destroyOnUnmount: true, // destroy() on unmount. Default: true for memory/local,
// false for indexedDB (a persistent storage is not wiped).
},
)
// Returned object (discriminated union on isReady):
// storage: ISyncStorage<TodoState> | null — non-null only when isReady === true
// isReady: boolean — the storage is created and initialized
// isLoading: boolean — initialization is in progress
// hasError: boolean — initialization failed
// status: { status, error? } — raw status (status.error?.message)
// initialize: () => Promise<void> — manual start (when autoInitialize: false)
// destroy: () => Promise<void> — manual destructionLifecycle options
| Field | Type | Default | Description |
|---|---|---|---|
| autoInitialize | boolean | true | Automatically call initialize() on mount. |
| destroyOnUnmount | boolean | true (memory/local), false (idb) | Destroy the storage on unmount. |
See also
MemoryStorage — the same storage at the module level (the global variant).
useCreateStorage (localStorage) · (indexedDB) — the same hook with persistence.
Subscriptions —
useStorageSubscribeand reactive reads.createSynapse — when you need a full-fledged module (selectors/dispatcher/effects).