Learn to build reusable custom React hooks with practical patterns for data fetching, local storage, media queries, and form state.

Abdur Razzak
Full-Stack Web Developer
Custom hooks let you extract and reuse stateful logic between components without changing the component tree. Before hooks, sharing stateful logic required render props or higher-order components — both of which add component nesting and complexity. A custom hook is simply a JavaScript function whose name starts with 'use' and that calls built-in React hooks inside it.
The useLocalStorage hook persists React state to localStorage automatically. Initialize state from localStorage on mount, and sync changes back to localStorage on every update. Handle JSON serialization and parsing, and protect against SSR environments where localStorage is not available. This hook is useful for user preferences, theme selection, and form draft saving.
A useFetch hook wraps the browser's fetch API with loading, error, and data states. Critically, use an AbortController and clean it up in the useEffect return function to cancel in-flight requests when the component unmounts. This prevents the 'Cannot update state on unmounted component' warning that causes memory leaks in React apps.
Debouncing delays a function call until a specified time has passed since the last invocation. The useDebounce hook returns a debounced value that only updates after the delay. Use it for search inputs to avoid firing an API request on every keystroke — instead, only fetch when the user pauses typing for 300-500ms. This reduces API calls by 90% on typical search interfaces.
The useMediaQuery hook listens to CSS media queries from JavaScript using the window.matchMedia API. This is useful when you need to conditionally render components based on screen size (not just style them). Unlike CSS-only solutions, useMediaQuery gives you a boolean in JavaScript that you can use in your component logic — for example, to render a mobile menu instead of a desktop nav.
Test custom hooks with the renderHook utility from @testing-library/react. Wrap hooks that need context providers in a wrapper option. Use act() to wrap state updates and async operations. Test the hook's initial state, its behavior after interactions, and edge cases like empty responses or network errors. Well-tested hooks can be shared across projects as an internal npm package or module.