What is a Custom Hook?
A custom hook is simply a JavaScript function whose name starts with "use" and that calls other hooks inside it. It lets you extract stateful logic out of a component so it can be reused across multiple components.
The Problem: Duplicated Stateful Logic
When the same pattern of useState and useEffect calls shows up in several components (like tracking window size, or fetching data), copy-pasting that logic everywhere becomes hard to maintain.
A Custom Hook: useWindowWidth
import { useState, useEffect } from "react";
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;
}Using the Custom Hook
function ResponsiveBanner() {
const width = useWindowWidth();
return <p>{width < 600 ? "Mobile view" : "Desktop view"}</p>;
}
function Sidebar() {
const width = useWindowWidth(); // reused, with its own independent state
return <aside style={{ display: width < 600 ? "none" : "block" }}>Sidebar</aside>;
}Each Call Gets Its Own State
Every component that calls a custom hook gets a completely independent copy of its internal state — calling useWindowWidth() in two components doesn’t share state between them, it just shares the logic.
A Custom Hook for Fetching Data
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(url)
.then((res) => res.json())
.then((json) => {
setData(json);
setLoading(false);
});
}, [url]);
return { data, loading };
}
function UserProfile({ userId }) {
const { data: user, loading } = useFetch(`/api/users/${userId}`);
if (loading) return <p>Loading...</p>;
return <h2>{user.name}</h2>;
}Rules for Custom Hooks
| Rule | Why |
|---|---|
| Name must start with "use" | Lets React (and linters) know it follows the Rules of Hooks |
| Only call hooks at the top level | Not inside loops, conditions, or nested functions |
| Only call hooks from React functions | Components or other custom hooks — never plain JavaScript functions |
Custom Hooks Are About Reusing Logic, Not UI
A custom hook shares behavior (stateful logic and side effects) between components, not JSX markup. To reuse JSX, write a regular component instead — the two techniques solve different problems and are often combined.
Best Practice
Extract a custom hook as soon as you copy-paste the same useState/useEffect pattern into a second component — it’s one of the most effective ways to keep React components focused and DRY.