Custom Hooks
- 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
- React, Reusing logic with custom Hooks — https://react.dev/learn/reusing-logic-with-custom-hooks