Skip to content

Custom Hooks

intermediate2 min read
  • React
  • TypeScript

Functions that extract reusable stateful logic out of components by calling built-in hooks, so several components can share behaviour without duplication.

Prerequisites

  • Built-in hooks and the Rules of Hooks (see Related Topics)

What you'll understand

  • What a custom hook is and why you would write one
  • How custom hooks share logic without sharing state
  • The naming and rules a custom hook must follow

Explanation

A custom hook is a JavaScript function whose name starts with use and that calls other hooks. It is the standard way to extract stateful logic out of a component so it can be reused. When two components need the same behaviour, tracking a form field, subscribing to the window size, fetching a resource, you move that logic into a custom hook and call it from each component.

The crucial idea is that custom hooks share logic, not state. Each component that calls a hook gets its own independent copy of any state inside it. Two components using the same useFormField hook do not share a value; they each get their own. This is what makes custom hooks reusable without coupling the components together.

Because a custom hook is itself a hook, it must obey the Rules of Hooks (see Related Topics): call it at the top level, and only from components or other hooks. A good custom hook has a clear purpose and a small return value, and it hides messy details, effect setup and cleanup, subscriptions, request handling, behind a simple interface, exactly as a well-named function should.

Examples

This custom hook encapsulates a common piece of logic and returns a simple value:

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    const onResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  return width;
}

Any component reuses that logic with a single call, each with its own state:

function Banner() {
  const width = useWindowWidth();
  return <p>{width < 600 ? "Mobile" : "Desktop"}</p>;
}

Common mistakes

  • Expecting two components using the same hook to share one piece of state.
  • Naming a hook without the use prefix, so the Rules of Hooks are not enforced.
  • Calling a custom hook conditionally instead of at the top level.
  • Cramming unrelated responsibilities into one hook instead of splitting them.

Best practices

  • Extract logic into a custom hook once it is duplicated across components.
  • Prefix the name with use and follow the Rules of Hooks (see Related Topics).
  • Give each hook a single, clear responsibility and a small return value.
  • Hide setup and cleanup inside the hook behind a simple interface.

Further reading

Related topics