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
stringThe localStorage key
initialValue
TThe 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>
);
}