Custom hooks

React chapter 14 · useControlled, useForkRef, useMediaQuery, useEventCallback · source: packages/mui-utils/src

The problem

The same open/close logic is copy-pasted into every panel. When a fix is needed, you must remember every copy, and one always gets missed.

The pattern that fixes it

Move the logic into a function named useX, call it at the top of each component, and return the state plus its actions. Fix it once and every caller gets the fix.

In plain words

A custom hook is just a function that uses other hooks and starts with use. It lets you package "state plus the rules around it" and reuse it, the way you reuse any other function.

Instead of writing the same recipe card by hand for every kitchen and fixing each card separately, you keep one master recipe. Each kitchen gets its own pot, but they all follow the same steps.

Terms

custom hook
Your own function whose name starts with use and that calls other hooks such as useState.
rules of hooks
Call hooks at the top level of a component or another hook, never inside if, loops or nested functions, so React can match them up by order.
return shape
What the hook gives back, like { open, toggle, close }. Keep it stable so callers do not break.

Going deeper

How does it work?

A hook is not a special object: React tracks the hook calls made while a component renders, in order. A custom hook simply runs its useState and friends inside the calling component, so each call gets its own private state. Two panels using useDisclosure() share the code but not the data.

When it goes wrong

Calling a hook conditionally breaks the order and React throws errors or mixes up state. A hook that returns a new object or function every render can defeat memo downstream, so wrap returned callbacks in useCallback. A hook that returns JSX is usually a component in disguise. Sharing a hook does not share state; for that you need context or a store.

When NOT to use it, and modern alternatives

Do not extract after one use, or for a single useState line with no rules around it. Extract when logic repeats, when a component mixes unrelated concerns, or when you want to test behavior alone. For data fetching or subscriptions prefer a proven library or useSyncExternalStore. MUI is built this way: useControlled, useForkRef and useMediaQuery are hooks first, components second.

Keep learning

More courses

  • Jobs, linked to lessons — Browse jobs where every requirement links to the chapter that teaches it. See how ready you are, how long the gap takes to close, and which listings look stale.
  • Match a job post to courses — Paste a job post. Each skill is matched to a track here and put in learning order, foundations first.
  • Database in depth — How a query becomes work. Indexes, isolation, locks, and the plans that explain why a page is slow — not an ORM tour.
  • System Design — Eight interview case studies, from a flash sale and Tatkal to a live final and a chat model, plus JWT in separate chapters.
  • Microservices — Microservice patterns one diagram at a time: how to split a monolith, how services talk, and how data stays consistent without distributed transactions.
  • Kafka — A beginner-to-senior path through event logs, reliable delivery, production operations, and disaster recovery.
  • Frontend system design — How a UI is sliced when it is a product, not a page: ownership of state, cache, routes, and what happens when the network lies.
  • CSS in depth — See the box, then the page. Visual chapters from the box model through Flexbox surprises, Grid, selectors, and units, then backgrounds, shapes, and visual effects, each with a playground.
  • Accessibility — HTML labs first, then a full pass of WAI-ARIA 1.3: naming, every state, widget and structure roles, live regions, ariaNotify, and relationships.
  • Docker — What an image is, why layers cache, and how containers find each other on a network.
  • Redis — Fifteen Redis patterns, one picture each: cache, session, lock, counter, rate limiter, queue, and when Redis is the wrong tool.