useLocalStorage — Persistent State Hook
Sync React state with localStorage including SSR safety, JSON serialization, and cross-tab updates.
import { useState, useEffect, useCallback } from 'react';
export function useLocalStorage<T>(
key: string,
initialValue: T
): [T, (value: T | ((prev: 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) as T) : initialValue;
} catch {
return initialValue;
}
});
const setValue = useCallback(
(value: T | ((prev: T) => T)) => {
setStoredValue((prev) => {
const next = value instanceof Function ? value(prev) : value;
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(next));
}
return next;
});
},
[key]
);
useEffect(() => {
const handler = (e: StorageEvent) => {
if (e.key === key && e.newValue) {
setStoredValue(JSON.parse(e.newValue) as T);
}
};
window.addEventListener('storage', handler);
return () => window.removeEventListener('storage', handler);
}, [key]);
return [storedValue, setValue];
}
// Usage:
// const [theme, setTheme] = useLocalStorage('theme', 'dark');Use Cases
- User preferences
- Theme persistence
- Form draft saving
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
usePrevious Hook
Track the previous value of any state or prop using a ref-based hook for comparison logic.
useFormValidation Hook
Lightweight form validation hook with field-level errors, touched tracking, and submit handling.
useFetch — Generic Data Fetching Hook
Custom React hook for data fetching with loading, error, and refetch states using the Fetch API.
useDebounce — Debounced Value Hook
Debounce any rapidly-changing value with a configurable delay. Useful for search inputs and resize handlers.