Write a reusable useDebouncedValue(value, delay) hook and explain when to build a custom hook.
Composition — extracting stateful logic (not UI) for reuse. Core to a shared component library.
A custom hook is just a function that calls other hooks; it lets you share stateful LOGIC without sharing UI or resorting to HOCs/render-props. useDebouncedValue keeps a debounced copy of a value in state and updates it via a timer that resets on each change, cleaning up the timer on change/unmount. Build a custom hook when the same use-of-hooks pattern (fetching, subscriptions, form state, media queries) repeats across components. Two properties make custom hooks powerful and safe: each call site gets its OWN isolated state (two components using useDebouncedValue don't share a timer), because a custom hook is a code-reuse mechanism, not a shared-state mechanism — for shared state you still need context or a store. And they compose: a useSearch hook can call useDebouncedValue and useFetch internally, building higher-level behavior from lower-level hooks the same way functions compose. Naming matters mechanically — the use prefix is what lets the linter enforce the Rules of Hooks inside them. The design guideline react.dev gives: a good custom hook wraps a concrete, nameable behavior ('debounce a value', 'track online status') rather than being a grab-bag of unrelated logic, and it returns the minimal interface its callers need.
Search inputs (debounce), data fetching, form handling, window/media listeners — any repeated stateful behavior.