Lesson 18 / 25
Custom Hooks
Reuse stateful logic, not state.
Functions that call hooks
A custom hook is a function whose name starts with use and that calls other hooks. It packages reusable logic: toggles, form fields, media queries, online status, fetching. Each component that calls the hook gets its own state; hooks share logic, not data. Return what callers need (values and functions), keep the API small, and test hooks through components that use them.
A useToggle hook used by two components, run
I ran this with React 19.3 and react-dom 19.3 on Node.js 22, compiling JSX with esbuild 0.28. Browser-style examples use jsdom 29 as a fake DOM (imported from a small setup-dom.mjs file) and act() to apply updates. Two FAQ items use the same useToggle hook. Clicking only the first question opens only its answer: each component instance keeps its own state.
import "./setup-dom.mjs"; // test setup: jsdom provides a browser-like DOM in Node
import { useState, useCallback, act } from "react";
import { createRoot } from "react-dom/client";
function useToggle(initial = false) {
const [on, setOn] = useState(initial);
const toggle = useCallback(() => setOn(v => !v), []);
return [on, toggle];
}
function FAQ({ q, a }) {
const [open, toggle] = useToggle();
return <div><button onClick={toggle}>{q}</button>{open && <p>{a}</p>}</div>;
}
const root = createRoot(document.getElementById("root"));
await act(() => root.render(<><FAQ q="Refunds?" a="Within 14 days." /><FAQ q="Shipping?" a="3-5 days." /></>));
const [first] = document.querySelectorAll("button");
await act(() => first.click());
console.log([...document.querySelectorAll("p")].map(p => p.textContent)); // each FAQ has its own state
Output:
[ 'Within 14 days.' ]
Name hooks after what they do
useOnlineStatus, useDebouncedValue and useCart say what they provide; vague names like useData hide intent.
Quick check: Do two components using the same custom hook share its state?
- No, each call gets its own independent state
- Yes, always
- Only on the server
- Only if they are siblings
Answer
No, each call gets its own independent state — Hooks share logic, not state.