React Custom Hooks Guide: How to Extract Reusable Logic Cleanly
Web

React Custom Hooks Guide: How to Extract Reusable Logic Cleanly


Once you study React a bit, repeated patterns start showing up everywhere. The same useState, useEffect, and event handling logic appears in multiple components, and many people wonder whether the answer is “make another component.” If the repetition is in logic rather than UI, a custom hook is often the better fit.

Custom hooks can sound advanced, but the basic idea is simple: wrap related React hook logic inside a reusable function. Once that clicks, components become easier to read because they can focus more on UI and less on repeated wiring.

This post covers three things.

  • when a custom hook is worth creating
  • how a hook differs from a component
  • practical examples that make good practice projects

The main takeaway is this: if the screens differ but the state behavior is the same, think about a custom hook before another component abstraction.

What a React custom hook is

A custom hook is a function whose name starts with use and which can call other React hooks internally. Its job is not to reuse UI. Its job is to reuse stateful logic and side-effect behavior.

For example, window resize tracking often repeats across many components.

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    function handleResize() {
      setWidth(window.innerWidth);
    }

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return width;
}

Now any component can call const width = useWindowWidth(); and stay focused on rendering.

When a custom hook is a good idea

A custom hook is often worth it when:

  • a useState and useEffect pattern repeats across files
  • several screens share the same state transitions
  • loading, error, or retry behavior keeps repeating
  • one component has become hard to read because the logic is too long

If the repeated part includes JSX structure and visual output, a component may be the better answer. The distinction is simple: hooks reuse logic, components reuse UI.

How hooks and components differ

Components return rendered output. Hooks return values, functions, and behavior.

A good example is modal behavior.

  • Modal: draws the actual layer and markup
  • useModal: manages whether it is open and how it opens or closes
function useModal() {
  const [open, setOpen] = useState(false);

  return {
    open,
    openModal: () => setOpen(true),
    closeModal: () => setOpen(false),
    toggleModal: () => setOpen((prev) => !prev),
  };
}

This lets different screens reuse the same modal behavior while keeping the rendered UI flexible.

Good practice hooks for beginners

It helps to start with small, concrete wins rather than trying to build a huge all-purpose hook.

Some good practice ideas are:

  • useToggle
  • useInput
  • useDebounce
  • useFetchPosts
  • useModal

These are great because they naturally combine state, effects, cleanup, and naming decisions in a manageable way.

Common mistakes

1. Making the hook too generic too early

A hook with too many options and branches can become harder to understand than the duplicated code it replaced.

2. Hiding UI concerns inside the hook

If the hook starts deciding button labels, markup structure, or styling classes, responsibilities are getting mixed.

3. Returning an unclear API

The return value is the public contract of the hook. If that contract is confusing, the callers will also be confusing.

A small example: debounced input

If you want to reduce how often a search query triggers requests, a debounce hook is a good practice case.

function useDebounce(value, delay = 300) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
}

This is a small hook, but it touches state, effect cleanup, and dependency handling all at once, which makes it an excellent learning project.

Questions to ask before extracting a hook

  1. Is the repeated thing UI or logic?
  2. Can I name this behavior clearly?
  3. What is the smallest useful API to return?
  4. Does the hook keep effect and cleanup responsibility contained?
  5. Is this hook trying to do too many jobs?

If the answers stay clear, the hook will make the codebase easier to understand instead of more abstract.

FAQ

Q. Can a custom hook call other hooks?

Yes. That is the normal pattern as long as React hook rules are followed.

Q. When should I move a hook into its own file?

If more than one component can use it, or if it makes the current file significantly easier to read, that is often enough reason.

Q. Can too many custom hooks make code harder to follow?

Yes. That is why naming and clear responsibility matter more than the number of hooks.

Start Here

Continue with the core guides that pull steady search traffic.