Capítulo 34 de 116

Chapter 34: Referencing Values with Refs

Core Idea

useRef gives a component a mutable "box" ({ current: value }) that persists across renders like state, but changing it does not trigger a re-render and reading/writing it doesn't follow the snapshot rules from Ch 23 — use it for values a component needs to remember that shouldn't affect what's on screen.

Key Concepts

  • const ref = useRef(initialValue): returns a plain object with one mutable property, ref.current, initialized to initialValue. That object identity stays stable across the component's entire lifetime.
  • Ref vs. state — the core differences: useState's setter queues a re-render; mutating ref.current does not re-render at all. State follows the snapshot model (Ch 23, fixed within a render); ref.current is a live, mutable value you can read and write mid-render or in a handler without waiting for the next render.
  • When to use a ref: storing a timeout/interval ID, tracking whether a component is still mounted, counting renders for debugging, or holding any value that's needed for logic but should never itself cause a re-render.
  • Best practice — treat refs as an escape hatch: don't read or write ref.current during rendering (only in event handlers or Effects) — since ref changes aren't tracked, reading one during render makes the component's output unpredictable, defeating the purity model from Ch 18.
  • Refs and the DOM (preview): passing a ref to a JSX element's ref attribute makes React populate ref.current with the actual underlying DOM node once mounted — the mechanism explored fully in Ch 35.

Code Examples

function StopwatchButtons() {
  const intervalRef = useRef(null); // survives renders, doesn't cause them

  function handleStart() {
    intervalRef.current = setInterval(() => { /* tick */ }, 1000);
  }
  function handleStop() {
    clearInterval(intervalRef.current);
  }
  return <>{/* buttons calling handleStart/handleStop */}</>;
}
  • What it demonstrates: storing an interval ID in a ref — needed across multiple event handler calls, but irrelevant to what renders on screen, so a ref (not state) is the right tool.

Key Takeaways

  1. If mutating a value should make the screen update, it's state; if it shouldn't (and updating on every mutation would be wasteful or wrong), it's a ref.
  2. Never read/write ref.current during the render body itself — confine ref access to event handlers and Effects, keeping rendering pure.
  3. A ref's identity (the object itself) is stable across renders, which is exactly why it's safe to stash things like interval IDs in it between handler calls.

Connects To

  • Ch 21 (State: A Component's Memory): the direct contrast this chapter draws against.
  • Ch 35 (Manipulating the DOM with Refs): refs' other major use case — holding a reference to an actual DOM node.
  • Ch 62 (useRef): the full API reference.