CodeOath
← All posts
React75 min total · 17 parts

React Fundamentals: Components, Hooks, and the Virtual DOM

Contents — Part 13 of 17: Custom Hooks
Part 13 of 17 · ~1 min

Custom Hooks

A custom hook is just a regular function that calls other hooks — the convention of naming it useSomething is how React's linter recognizes it as a hook (and enforces the Rules of Hooks on it), not special syntax.

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

function Settings() {
  const [name, setName] = useLocalStorage("name", "");
  return <input value={name} onChange={(e) => setName(e.target.value)} />;
}

This is where React's real reusability comes from — extracting stateful logic (not just UI) into a function that any component can call, exactly like useState and useEffect themselves.

The Rules of Hooks

  1. Only call hooks at the top level — never inside a loop, condition, or nested function. React relies on hooks being called in the exact same order on every render to correctly match each useState call to its corresponding piece of state; conditionally skipping a hook call shifts every hook after it.
  2. Only call hooks from React function components or other custom hooks — never from a plain JavaScript function, class component, or outside a component entirely.

Both rules exist for the same reason: React identifies each piece of hook state by call order, not by name — there's no "count" string tying useState(0) to a specific slot; it's purely "the 3rd hook call in this component."