The Codex / Technologies / React / Hooks Deep Dive

Hooks Deep Dive

The rest of React's built-in hooks - useRef, useReducer, useId, and the rules that govern how all hooks work together.

What it is, in plain English: Beyond useState and useEffect, React provides several more built-in hooks for specific jobs: useRef holds a mutable value that persists across renders without triggering re-renders (often used for DOM references). useReducer manages complex state logic with multiple sub-values via a reducer function, similar to Redux. useId generates unique IDs for accessibility attributes. Understanding these fills out the complete hooks toolkit for building real applications.

useRef -- a box that doesn't trigger re-renders

useState causes a re-render every time you update it. Sometimes you need to remember a value across renders WITHOUT causing a re-render -- that's what useRef is for.

The most common use -- accessing a DOM element

function TextInputWithFocusButton() {
  const inputRef = React.useRef(null);

  function handleClick() {
    inputRef.current.focus();   // .current gives you the actual DOM node
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>Focus the input</button>
    </>
  );
}

// React sets inputRef.current to the real <input> DOM element after it mounts.
// This is the standard way to call DOM methods (focus, scrollIntoView, play, etc.)
// that React doesn't have a declarative prop for.

useRef for storing any mutable value

function StopwatchTimer() {
  const [elapsed, setElapsed] = React.useState(0);
  const intervalRef = React.useRef(null);   // stores the interval ID

  function start() {
    intervalRef.current = setInterval(() => {
      setElapsed(e => e + 1);
    }, 1000);
  }

  function stop() {
    clearInterval(intervalRef.current);   // read the stored ID to clear it
  }

  return (
    <div>
      <p>{elapsed}s</p>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </div>
  );
}
// Key difference from useState: changing intervalRef.current does NOT
// cause a re-render. useRef is for values the component needs to remember
// but that should never directly cause the UI to update.

The Rules of Hooks, restated clearly

// 1. Only call hooks at the TOP LEVEL of a component or custom hook
//    (never inside if/for/while/nested functions)
// 2. Only call hooks from React function components or custom hooks
//    (never from regular JS functions or class components)

function GoodComponent() {
  const [a, setA] = React.useState(0);   // ✓ top level
  const ref = React.useRef(null);         // ✓ top level
  React.useEffect(() => {}, []);          // ✓ top level

  if (a > 5) {
    // const [b] = React.useState(0);    // ✗ would break the rules
  }
}
Try It Yourself (JSX)

Official Sources

The Codex links only to official documentation. No third-party tutorials.