Custom Hooks — reusable stateful logic

[check: …]
📖 guide (.md) ← react deep dive
📖 Pair this live React playground with the companion guide (.md) — this page is the rendered ground truth. ↗ Builds on frontend/react: useState (the primitive these hooks wrap) and frontend/react: useEffect (the effect primitive usePrevious uses).

what is a custom hook?

A custom hook is a plain JavaScript function whose name starts with use and that may call other hooks. It extracts the wiring of state + effects + refs into one reusable unit, so useState + useEffect + useRef boilerplate never has to be copy-pasted between components. The hook itself holds no state — each component that calls it gets its own isolated state. That is the whole point: shared logic, private state.

rulewhat it meanswhy it matters
1. name starts with use e.g. useToggle, useLocalStorage — capital U, then lowercase the linter (eslint-plugin-react-hooks) & Fast Refresh key off this prefix; without it they cannot detect hook violations
2. may call other hooks useState, useEffect, useReducer, even other custom hooks, freely inside this is what makes the logic "stateful" — composing hooks is composition of state machines
3. obeys the Rules of Hooks call hooks at the top level, never inside loops/conditions/nested functions React tracks hook state by call order — conditional calls break that bookkeeping
4. returns anything value, [value, setter] array, or {key, key} object — your choice convention: arrays for a single concept (caller renames), objects for many fields
5. takes anything initial values, callbacks, refs — pure arguments in, anything out hooks are just functions; params let callers configure behavior at the call site

1 · three hooks you write (edit me)

2 · Babel compiles JSX → element tree

<CustomHooksDemo/> becomes React.createElement(CustomHooksDemo). The three use* functions are ordinary JS — only their calls to React hooks are special. Each component instance owns a separate slot of state per hook call.

// (hit "compile & render" to see Babel's output)

3 · live React (three hooks, proven)

Click Flip to toggle useToggle, click + to drive useCounter while usePrevious trails the last value. The gold-check does this automatically: assert OFF → flip ON → flip OFF → inc (1/0) → inc (2/1) → reset (0/2).

live: · gold: OFF → ON → OFF → 1/0 → 2/1 → 0/2

common custom hooks catalog

hookwrapscommon use case
useToggle(initial) useState boolean on/off flags — modals, switches, accordions
usePrevious(value) useRef + useEffect access the previous value of any state/prop (diff detection)
useCounter(initial) useState + useCallback increment / decrement / reset numeric state with stable callbacks
useDebounce(value, ms) useState + useEffect delay a rapidly-changing value (search-as-you-type, resize)
useLocalStorage(key, init) useState + useEffect persist state across reloads; lazy-init from localStorage
useFetch(url) useState + useEffect data fetching with {data, loading, error} shape
useMediaQuery(query) useState + useEffect subscribe to CSS media queries, re-render on breakpoint change
useEventListener(target, event, fn) useRef + useEffect attach/detach DOM or window listeners with correct cleanup