SkillByAIOpen interactive version →

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.