useLocalStorage
A React hook for managing localStorage with automatic JSON serialization, type safety, and optional tab synchronization.
useLocalStorage
A powerful React hook for managing localStorage with automatic JSON serialization, type safety, and optional tab synchronization. This hook provides a clean API similar to useState
but with persistent storage capabilities.
Features
- π Type Safe: Full TypeScript support with automatic type inference
- π¦ Auto Serialization: Handles JSON serialization/deserialization automatically
- π Tab Sync: Optional synchronization across browser tabs
- π― Functional Updates: Supports both direct values and updater functions
- π§Ή Cleanup Methods: Built-in remove and clear functionality
- β‘ Custom Serializers: Support for custom serialization logic
Installation
npm install light-hooks
# or
yarn add light-hooks
# or
pnpm add light-hooks
Basic Usage
import { useLocalStorage } from 'light-hooks';
function UserProfile() {
const [user, setUser] = useLocalStorage('user', {
name: 'Anonymous',
preferences: { theme: 'light' }
});
return (
<div>
<h1>Welcome, {user.name}!</h1>
<button
onClick={() => setUser({ ...user, name: 'John Doe' })}
>
Update Name
</button>
</div>
);
}
API Reference
Parameters
Parameter | Type | Required | Description |
---|---|---|---|
key | string | β | The localStorage key to use |
initialValue | T | β | Initial value if no stored value exists |
options | UseLocalStorageOptions | β | Configuration options |
Options
interface UseLocalStorageOptions {
serializer?: {
stringify: (value: any) => string;
parse: (value: string) => any;
};
syncAcrossTabs?: boolean;
}
Return Value
interface UseLocalStorageReturn<T> {
value: T; // Current stored value
setValue: (value: T | ((prev: T) => T)) => void; // Update function
removeValue: () => void; // Remove from localStorage
clear: () => void; // Clear all localStorage
}
Examples
Basic String Storage
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
return (
<div>
<p>Current theme: {theme}</p>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
</div>
);
}
Complex Object Storage
interface ShoppingCart {
items: Array<{ id: string; name: string; quantity: number }>;
total: number;
}
function ShoppingCartManager() {
const [cart, setCart] = useLocalStorage<ShoppingCart>('cart', {
items: [],
total: 0
});
const addItem = (item: { id: string; name: string; price: number }) => {
setCart(prevCart => ({
items: [...prevCart.items, { ...item, quantity: 1 }],
total: prevCart.total + item.price
}));
};
const clearCart = () => {
setCart({ items: [], total: 0 });
};
return (
<div>
<h2>Cart ({cart.items.length} items)</h2>
<p>Total: ${cart.total}</p>
<button onClick={clearCart}>Clear Cart</button>
</div>
);
}
Functional Updates
function Counter() {
const [count, setCount] = useLocalStorage('counter', 0);
const increment = () => setCount(prev => prev + 1);
const decrement = () => setCount(prev => prev - 1);
const reset = () => setCount(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}
Tab Synchronization
function SyncedSettings() {
const [settings, setSettings] = useLocalStorage(
'app-settings',
{ notifications: true, autoSave: false },
{ syncAcrossTabs: true }
);
return (
<div>
<label>
<input
type="checkbox"
checked={settings.notifications}
onChange={(e) =>
setSettings(prev => ({
...prev,
notifications: e.target.checked
}))
}
/>
Enable Notifications
</label>
<label>
<input
type="checkbox"
checked={settings.autoSave}
onChange={(e) =>
setSettings(prev => ({
...prev,
autoSave: e.target.checked
}))
}
/>
Auto Save
</label>
</div>
);
}
Custom Serializer
function DateStorage() {
const [lastVisit, setLastVisit] = useLocalStorage(
'lastVisit',
new Date(),
{
serializer: {
stringify: (date: Date) => date.toISOString(),
parse: (dateString: string) => new Date(dateString)
}
}
);
return (
<div>
<p>Last visit: {lastVisit.toLocaleDateString()}</p>
<button onClick={() => setLastVisit(new Date())}>
Update Visit Time
</button>
</div>
);
}
Cleanup Operations
function DataManager() {
const [userData, setUserData, removeUserData, clearAll] = useLocalStorage(
'userData',
{ name: '', email: '' }
);
return (
<div>
<input
value={userData.name}
onChange={(e) => setUserData(prev => ({ ...prev, name: e.target.value }))}
placeholder="Name"
/>
<input
value={userData.email}
onChange={(e) => setUserData(prev => ({ ...prev, email: e.target.value }))}
placeholder="Email"
/>
<button onClick={removeUserData}>
Remove User Data
</button>
<button onClick={clearAll}>
Clear All Storage
</button>
</div>
);
}
TypeScript Support
The hook provides excellent TypeScript support with automatic type inference:
// Type is automatically inferred as string
const [name, setName] = useLocalStorage('name', 'John');
// Type is automatically inferred as number
const [age, setAge] = useLocalStorage('age', 25);
// Complex type with explicit generic
interface User {
id: number;
name: string;
preferences: {
theme: 'light' | 'dark';
language: string;
};
}
const [user, setUser] = useLocalStorage<User>('user', {
id: 1,
name: 'John',
preferences: {
theme: 'light',
language: 'en'
}
});
Best Practices
1. Use Meaningful Keys
// β Avoid generic keys
const [data, setData] = useLocalStorage('data', {});
// β
Use descriptive keys
const [userPreferences, setUserPreferences] = useLocalStorage('user-preferences', {});
2. Provide Sensible Defaults
// β
Always provide meaningful initial values
const [settings, setSettings] = useLocalStorage('app-settings', {
theme: 'light',
notifications: true,
autoSave: false
});
3. Handle Large Objects Carefully
// β
Be mindful of localStorage size limits (typically 5-10MB)
const [largeData, setLargeData] = useLocalStorage('large-data', []);
// Consider chunking or compression for very large datasets
4. Use Tab Sync Strategically
// β
Enable for user preferences that should sync
const [theme, setTheme] = useLocalStorage('theme', 'light', {
syncAcrossTabs: true
});
// β Avoid for form data or temporary state
const [formData, setFormData] = useLocalStorage('form-data', {});
Browser Compatibility
- β Modern browsers with localStorage support
- β Server-side rendering safe (returns initial value on server)
- β Graceful fallback when localStorage is unavailable
Common Use Cases
- π¨ Theme Preferences: Store user's dark/light mode preference
- π Shopping Cart: Persist cart items across sessions
- π Form Data: Auto-save form progress
- βοΈ User Settings: Store application preferences
- π Authentication: Persist user tokens (with proper security)
- π Analytics: Store user interaction data locally
Performance Considerations
- Changes are batched to avoid excessive localStorage writes
- JSON serialization only occurs when values actually change
- Tab synchronization uses efficient event listeners
- No unnecessary re-renders when localStorage changes externally
Need help with other hooks? Check out our complete hooks reference.