Custom hooks — reusing logic
Reusing logic, not just UI
Components let you reuse UI. But what about reusing logic — like the same data-fetching steps, or the same form handling, across many components? For that, React lets you write your own hook: a custom hook.
A custom hook is just a function whose name starts with use and that uses other hooks inside it.
Example: a useFetch hook
Remember our data-fetching pattern? Let us extract it once and reuse it everywhere:
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((d) => {
setData(d);
setLoading(false);
});
}, [url]);
return { data, loading };
}
Now any component can fetch in one line:
function Users() {
const { data, loading } = useFetch("https://.../users");
if (loading) return <p>Loading...</p>;
return <ul>{data.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}
The messy fetch logic is written once, used everywhere. Clean.
The rules of hooks (important)
Two simple rules keep hooks working correctly:
- Only call hooks at the top level of a component or custom hook — never inside
if, loops, or nested functions. - Only call hooks from React functions — components or other custom hooks, not plain functions.
Why custom hooks matter
They are how React apps stay DRY (Don't Repeat Yourself). Form handling, fetching, timers, localStorage — wrap any repeated logic in a use... hook, and your components become short and readable.
A custom hook is a
use...function that bundles reusable logic (built from other hooks). Write the logic once, share it across components. Follow the rules: hooks only at the top level, only in React functions.