React Hooks Patterns
Reusable custom hook patterns for UI state, data fetching, forms, persistence, and interaction handling.
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all
## Custom Hook Patterns
function useInterval({ callback, delay, enabled = true }: {
callback: () => void;
delay: number;
enabled?: boolean;
}) {
useEffect(() => {
if (!enabled) return;
const id = setInterval(callback, delay);
return () => clearInterval(id);
}, [callback, delay, enabled]);
}# Prefer options objects for extensible APIs.
## Common UI Hooks
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const raw = localStorage.getItem(key);
return raw ? JSON.parse(raw) as T : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}# Sync component state with localStorage.
function useMediaQuery(query: string) {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
setMatches(media.matches);
const onChange = () => setMatches(media.matches);
media.addEventListener('change', onChange);
return () => media.removeEventListener('change', onChange);
}, [query]);
return matches;
}# Expose a boolean that tracks a CSS media query.
function useOnClickOutside<T extends HTMLElement>(ref: React.RefObject<T>, onOutside: () => void) {
useEffect(() => {
function handle(event: MouseEvent) {
if (!ref.current || ref.current.contains(event.target as Node)) return;
onOutside();
}
document.addEventListener('mousedown', handle);
return () => document.removeEventListener('mousedown', handle);
}, [ref, onOutside]);
}# Close menus or popovers when a click happens outside a ref.
## Data Fetching Patterns
useEffect(() => {
const controller = new AbortController();
fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal: controller.signal })
.then(r => r.json())
.then(setResults)
.catch(err => {
if (err.name !== 'AbortError') throw err;
});
return () => controller.abort();
}, [query]);# Cancel stale requests on dependency change.
## Forms and Event Patterns
function formReducer(state: FormState, action: FormAction): FormState {
switch (action.type) {
case 'change':
return { ...state, [action.name]: action.value };
case 'reset':
return action.initial;
default:
return state;
}
}# Use a reducer when form behavior becomes more complex.
function useDebouncedValue<T>(value: T, delay: number) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const id = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(id);
}, [value, delay]);
return debounced;
}# Delay reactions to rapidly changing values.
More in React Hooks
React Hooks Recipes
Practical React Hooks recipes for UI interactions, timers, measurement, polling, and optimistic updates.
React Hooks with TypeScript
Type-safe React Hooks patterns for state, refs, reducers, and custom hooks.
React Hooks Pitfalls and Best Practices
Common React Hooks mistakes, stale closure issues, dependency pitfalls, and practical best practices.
React Hooks Cheat Sheet
Built-in React Hooks reference covering state, effects, refs, context, memoization, transitions, and store subscriptions.