Skip to content
RungsySign in

Custom Hooks

Extracting stateful logic so it stops being copy-pasted across six components.

35 minDifficulty 3/5react · patternsAI-writtenWritten by a model on 16 August 2026 and not yet read by a person. Checked automatically: schema, the pedagogical rules the hand-written material is held to, and every diagram parsed for real.

Before this

Why this exists

Six different components each implement their own "track whether the mouse is hovering this element" logic — a `useState`, an `onMouseEnter`, an `onMouseLeave`, copy-pasted with minor variations six times. A custom hook extracts that logic into one function, `useHover()`, that any component can call to get the exact same behaviour with zero duplication.

The mental model

A custom hook is just a regular JavaScript function that happens to call other hooks inside it — there's no special syntax or registration step. Naming it `useSomething` is a convention, not magic, but it's a convention React's linter relies on to enforce the rules of hooks correctly for your custom one too.

How it works

Extraction, not sharing state — each call gets its own instance

Calling `useHover()` in three different components gives each one its OWN independent state — hovering one doesn't affect the others. A custom hook shares LOGIC (the pattern of state plus effects plus handlers), not the underlying state itself, which stays private to whichever component called the hook.

A custom hook can compose other hooks freely

`useFetch(url)` might internally use `useState` for the data, `useState` for loading and error flags, and `useEffect` to trigger the actual request — the consuming component sees none of that internal complexity, just `const { data, loading, error } = useFetch(url)`. Composing hooks this way is how complex stateful logic gets packaged into a simple, reusable interface.

The useX naming convention isn't optional if you call hooks inside

React's rules-of-hooks linter identifies which functions are hooks by name — anything starting with `use` gets checked for correct hook usage (called at the top level, not conditionally). A function that calls `useState` internally but isn't named `useSomething` won't be checked by the linter, silently allowing rule violations that would otherwise be caught.

Extract when the same stateful pattern repeats, not preemptively

The first time you write 'fetch data, track loading, track error' inline in a component is fine. The third time you're about to copy-paste that same pattern is the signal to extract it into a custom hook — extracting after one use, before knowing the actual variations needed across call sites, tends to produce an interface that doesn't fit the second real use case.

The mechanism

A custom hook is defined as a plain function, conventionally named useSomething, that calls one or more built-in hooks internally. When a component calls this custom hook, React associates that call with the component's own internal state slot — same as if the component had called useState directly — so each calling component gets an independent, isolated instance of whatever state the hook manages.

What people get wrong

Two components calling the same custom hook share the same state.
Each call to a custom hook gets its own independent copy of whatever state that hook manages internally — the hook shares the PATTERN of logic, not a single shared value. This confusion leads people to expect a custom hook alone to solve cross-component state sharing, when that actually requires lifting state up or using context, a separate concern from hook extraction.
Any function that returns state and a setter counts as a hook, regardless of naming.
The `use` prefix is what React's ESLint rules-of-hooks plugin looks for to apply its checks — a function doing the same thing without that prefix won't be linted for hook rule violations, even though it behaves identically at runtime. Skipping the naming convention doesn't break anything immediately, but it silently disables the safety net that catches conditional hook calls and other rule violations before they cause bugs.
You should extract a custom hook the first time you write any stateful logic, to keep components clean.
Premature extraction, before a pattern has actually repeated, tends to produce an interface shaped around one use case that doesn't fit the second real caller, requiring an awkward refactor anyway. Extracting too early optimizes for a reuse that may never materialize, or materializes with different needs than the first extraction anticipated.

When not to use it

The logic doesn't involve any React hooks internally — it's pure computation on inputs.
A plain utility function, not a custom hook — the `use` prefix and hook rules add no value if nothing inside actually calls React's hooks.
Multiple components genuinely need to share the SAME state value, not just the same pattern of logic.
Lift the state to a common ancestor and pass it down, or use context — a custom hook alone gives each caller independent state, which doesn't solve sharing.

Terms

Custom hook
A function, conventionally named useSomething, that extracts reusable stateful logic by calling one or more built-in hooks internally.
Rules of hooks
The constraints hooks must follow — called only at a component's top level, never conditionally or in a loop — enforced by React's ESLint plugin for functions named with the use prefix.
Hook composition
Building a custom hook out of multiple other hooks (built-in or custom) to package complex behaviour behind a simple interface.
State isolation
The property that each component calling a custom hook gets its own independent instance of that hook's internal state, not a shared one.

Can you recall it?

If three different components each call the same custom hook, do they share state? Why or why not?

Keep track of this

Add React Fundamentals to your map and Rungsy will schedule reviews so you actually remember it.