useLocalStorageState

State Management

A React hook that persists state in localStorage, automatically syncing between tabs and windows.

Demo

This counter persists across page refreshes and syncs between tabs:

0

Installation

npm install @thibault.sh/hooks

Usage

import { useLocalStorageState } from '@thibault.sh/hooks/useLocalStorageState';

function ThemeToggle() {
  const [theme, setTheme] = useLocalStorageState('theme', 'light');
  
  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      Current theme: {theme}
    </button>
  );
}

API

Parameters

  • key
    string

    The localStorage key

  • initialValue
    T

    The initial value to use if no value exists in storage

Returns

A tuple containing the current value and a setter function

Features

  • Persistent Storage

    Data persists between page refreshes

  • Cross-Tab Synchronization

    State syncs across browser tabs

  • Type Safety

    Full TypeScript support with generics

  • Automatic Serialization

    JSON serialization handled automatically

User Preferences Example

import { useLocalStorageState } from '@thibault.sh/hooks';

interface UserPreferences {
  theme: 'light' | 'dark';
  fontSize: number;
  notifications: boolean;
}

function UserSettings() {
  const [preferences, setPreferences] = useLocalStorageState<UserPreferences>(
    'user-preferences',
    {
      theme: 'light',
      fontSize: 16,
      notifications: true,
    }
  );

  const toggleTheme = () => {
    setPreferences(prev => ({
      ...prev,
      theme: prev.theme === 'light' ? 'dark' : 'light',
    }));
  };

  return (
    <div>
      <h2>User Settings</h2>
      <button onClick={toggleTheme}>
        Toggle Theme ({preferences.theme})
      </button>
      <input
        type="number"
        value={preferences.fontSize}
        onChange={(e) => 
          setPreferences(prev => ({
            ...prev,
            fontSize: Number(e.target.value),
          }))
        }
      />
    </div>
  );
}

Shopping Cart Example

import { useLocalStorageState } from '@thibault.sh/hooks';

interface CartItem {
  id: string;
  quantity: number;
}

function ShoppingCart() {
  const [cart, setCart] = useLocalStorageState<CartItem[]>('shopping-cart', []);

  const addItem = (id: string) => {
    setCart(prev => {
      const existing = prev.find(item => item.id === id);
      if (existing) {
        return prev.map(item =>
          item.id === id
            ? { ...item, quantity: item.quantity + 1 }
            : item
        );
      }
      return [...prev, { id, quantity: 1 }];
    });
  };

  return (
    <div>
      <h2>Cart ({cart.length} items)</h2>
      {cart.map(item => (
        <div key={item.id}>
          Product {item.id}: {item.quantity}x
        </div>
      ))}
    </div>
  );
}