@guoyunhe/react-storage
v2.0.3
Published
React hooks for localStorage and sessionStorage with JSON serialization, custom serializer/parser, key prefix, and SSR-safe fallback
Maintainers
Readme
@guoyunhe/react-storage
React hooks for localStorage and sessionStorage — JSON serialization, custom serializer/parser, key prefix namespacing, and real-time cross-tab sync. SSR-safe with zero direct dependencies.
Features
- 🪝
useState-like API — drop-in replacement with the same[value, setValue]tuple - 🔄 Cross-tab sync — state stays in sync across browser tabs via the native
storageevent - 🧩 Custom serializer/parser — store
Date,Map, or any custom type - 📦 JSON by default — objects and arrays work out of the box
- 🏷️ Key prefix — namespace storage keys per app via
<StorageProvider> - 🌐 SSR-safe — no
windowaccess during render, works with Next.js and Remix - 🪶 Tiny bundle — zero runtime dependencies, tree-shakable ESM
- 💪 TypeScript first — fully typed with generics
Install
npm install --save @guoyunhe/react-storageQuick Start
import { useLocalStorage, useSessionStorage } from '@guoyunhe/react-storage';
function App() {
const [settings, setSettings] = useLocalStorage('settings', {
theme: 'dark',
fontSize: 14,
});
const [draft, setDraft] = useSessionStorage('draft', '');
}Guides
Custom types (Date, Map, etc.)
Use serializer and parser to handle non-JSON types:
const [date, setDate] = useLocalStorage('date', new Date(), {
serializer: (d) => d.toISOString(),
parser: (s) => new Date(s),
});Key prefix for multi-app domains
Scope storage keys per app to avoid collisions:
import { StorageProvider, useLocalStorage } from '@guoyunhe/react-storage';
function App() {
return (
<StorageProvider prefix='dashboard_'>
<Dashboard />
</StorageProvider>
);
}
function Dashboard() {
// actual key: "dashboard_theme"
const [theme, setTheme] = useLocalStorage('theme', 'light');
}Global serializer/parser
Set defaults once at the top level:
<StorageProvider serializer={mySerializer} parser={myParser} prefix='app_'>
<App />
</StorageProvider>Cross-tab counter
All components reading the same key stay in sync — even across tabs:
function Counter() {
const [count, setCount] = useLocalStorage('count', 0);
return (
<div>
<button onClick={() => setCount((c) => c - 1)}>−</button>
<span>{count}</span>
<button onClick={() => setCount((c) => c + 1)}>+</button>
</div>
);
}
// Render multiple <Counter /> — they all share the same stateAPI
useLocalStorage<T>(key, defaultValue, options?)
Returns [value, setValue] — same shape as useState. Values persist in localStorage and sync across tabs.
useSessionStorage<T>(key, defaultValue, options?)
Same API as useLocalStorage, but stores in sessionStorage. Data is cleared when the tab closes. Useful for draft forms, wizard state, and ephemeral UI state.
options
| Option | Type | Default | Description |
| ------------ | ---------------------- | ---------------- | --------------------------------------- |
| serializer | (value: T) => string | JSON.stringify | Custom serialize function |
| parser | (raw: string) => T | JSON.parse | Custom parse function |
| prefix | string | '' | Override the global prefix for this key |
<StorageProvider>
Provides global defaults for all hooks within its subtree.
| Prop | Type | Default | Description |
| ------------ | ------------------------ | ---------------- | ----------------- |
| serializer | (value: any) => string | JSON.stringify | Global serializer |
| parser | (raw: string) => any | JSON.parse | Global parser |
| prefix | string | '' | Global key prefix |
Comparison
| | @guoyunhe/react-storage | use-local-storage-state | usehooks-ts | react-use | ahooks |
| ----------------- | :---------------------: | :---------------------: | :---------: | :-------: | :------: |
| React peer | >=16.8 | >=18 | >=16.8 | * | >=16.8 |
| Dependencies | 0 | 0 | 1 | 14 | 10 |
| Local + Session | ✅ | ❌ | ✅ | ✅ | ✅ |
| Cross-tab sync | ✅ | ✅ | ❌ | ❌ | ✅ |
| Key prefix | ✅ | ❌ | ❌ | ❌ | ❌ |
| Custom serializer | ✅ | ✅ | ✅ | ❌ | ✅ |
| Typed API | ✅ | ✅ | ✅ | ✅ | ✅ |
| ESM | ✅ | ✅ | ✅ | ✅ | ✅ |
