Skip to content

Repository files navigation

@guoyunhe/react-storage

npm version npm downloads bundle size socket security license

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 storage event
  • 🧩 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 window access 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-storage

Quick 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 state

API

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

License

MIT

About

Better useLocalStorage() and useSessionStorage() hooks

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages