A custom hook is a function whose name starts with use and that may call other hooks. It extracts reusable stateful logic—form fields, media queries, debounced search—without inheritance or HOC wrappers.
Rules
- Only call hooks at the top level of the custom hook (and React components)
- Return whatever API fits: values, setters, dispatch, refs
- Keep hooks focused; compose smaller hooks instead of one “god hook”
Example pattern
function useCounter(start = 0) {
const [n, setN] = React.useState(start);
const inc = () => setN((c) => c + 1);
const reset = () => setN(start);
return { n, inc, reset };
}
Testing hooks is easier when logic lives in a hook tested via @testing-library/react renderHook utilities.
Self-check
- Why must the function name start with
use? - What belongs in a hook vs a plain utility function?
Challenge
Extract useToggle
- Copy the toggle logic into
function useToggle(initial). - Use it in
Appand confirm the button still works.
Done when: toggle behavior unchanged after extraction.
Challenge
Rename to useFormField
- Extract value + onChange into
useFormField(initial). - Wire two inputs with two hook instances.
Done when: both fields update independently with shared hook logic.