Custom Hooks
Chapter 2's useTheme was already a custom hook, introduced without dwelling on the concept itself. A custom hook is nothing more than a regular JavaScript function whose name starts with use, which calls other hooks inside it — there's no special syntax, no registration step, no library involved. It exists purely to pull repeated stateful logic (state plus the behavior around it) out of components and into something reusable, the same way a regular function extracts repeated non-stateful logic.
The Simplest Possible Custom Hook
useToggle wraps a useState call and the boolean-flip logic that goes with it (the same pattern as Fundamentals Chapter 3's LightSwitch), so any component needing toggle behavior can call one hook instead of writing the flip function itself every time. It returns a tuple, like useState does, purely as a convention — a custom hook can return anything at all (an object, a single value, several values).
useLocalStorage — Syncing State with the Browser
This is exactly the load/save pair Project 3's stretch goals suggested extracting — two effects' worth of localStorage logic, now living in one hook instead of being duplicated in every component that needs persistence. Passing a function to useState (rather than a plain value) is worth noting here: that initializer function only runs once, on the very first render, rather than re-reading localStorage on every single re-render.
useDebounce — Delaying a Fast-Changing Value
This is the Book Search project's debounce logic, lifted out of a component and into a reusable hook — exactly the stretch goal it suggested. useDebounce takes a fast-changing value (query, updated on every keystroke) and returns a second value that only catches up after delay milliseconds of no further changes, using the same setTimeout + cleanup pattern from Fundamentals Chapter 8 and Project 4, just packaged for reuse anywhere a debounced value is needed.
useState, useEffect, useContext, or another hook internally. If two or more components are duplicating the same stateful behavior, that's usually the moment to extract it.
use prefix isn't just a naming convention; tools like the ESLint hooks plugin specifically look for that prefix to know which functions to apply these rules to.
Coding Challenges
Write the useToggle hook from this chapter and use it in two different components — one toggling a sidebar's open/closed state, one toggling a "show password" boolean on a password input.
📄 View solutionWrite the useLocalStorage hook from this chapter, and use it to persist a simple counter's current value, confirming it survives a page refresh.
📄 View solutionWrite the useDebounce hook from this chapter. Build a search input where the raw value updates on every keystroke, and a separate debounced value (400ms) is displayed below it once typing pauses — enough to see the two values catch up to each other after a short delay.
📄 View solutionChapter 4 Quick Reference
- A custom hook is just a function starting with use that calls other hooks inside it
- Extract one when several components duplicate the same stateful logic — not just any repeated code
- useToggle — boolean state + a flip function, wrapped for reuse
- useLocalStorage — a drop-in
useStatereplacement that persists automatically - useDebounce — returns a value that only catches up after a pause in changes
- Custom hooks still follow the rules of hooks — top-level calls only, no conditionals
- Next chapter: React Router — multiple pages in a single-page app, first previewed in Project 4