useLocalStorage Hook
April 25, 2025
Persisting state to localStorage is a common need — for user preferences, form drafts, or theme settings. This hook makes it easy to sync React state with localStorage.
import { useState, useEffect } from 'react';
export function useLocalStorage<T>(
key: string,
initialValue: T
): [T, (value: T | ((val: T) => T)) => void] {
const [storedValue, setStoredValue] = useState<T>(() => {
if (typeof window === 'undefined') {
return initialValue;
}
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value: T | ((val: T) => T)) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
How It Works
- On mount, reads from localStorage and initializes state.
- Updates both state and localStorage when value changes.
- Handles SSR by checking for
window. - Supports functional updates like
useState.
Example Usage
function ThemeToggle() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<button onClick={toggleTheme}>
Current theme: {theme}
</button>
);
}
More Examples
// Form draft persistence
const [draft, setDraft] = useLocalStorage('form-draft', '');
// User preferences
const [preferences, setPreferences] = useLocalStorage('user-prefs', {
notifications: true,
language: 'en'
});
Use Cases
- Theme preferences (dark/light mode)
- Form draft saving
- User settings
- Shopping cart persistence
- Recently viewed items
Notes
- Only works with JSON-serializable values.
- Handles SSR gracefully by checking for
window. - Automatically syncs across tabs (localStorage is shared).
- For complex objects, ensure they're JSON-serializable.
A simple hook that bridges React state and browser storage, making persistence effortless.