Capítulo 35 de 116

Chapter 35: Manipulating the DOM with Refs

Core Idea

Passing a ref to a built-in element's ref attribute gives you direct, imperative access to the underlying DOM node (for things React's declarative model doesn't cover, like focusing, scrolling, or measuring) — but this should stay a targeted escape hatch, not the default way to change what's on screen.

Key Concepts

  • Getting a ref to a node: const inputRef = useRef(null), then <input ref={inputRef} /> — after mount, inputRef.current is the real DOM element, letting you call imperative browser APIs (.focus(), .scrollIntoView(), .measure()-style reads) directly.
  • Accessing another component's DOM node: by default, a custom component doesn't expose its inner DOM node to a ref the way a built-in element does — a component needs to explicitly forward that access (historically via forwardRef, and directly via a ref prop in modern React) if a parent needs to reach into its rendered DOM.
  • When React attaches refs: refs are attached after the commit phase (Ch 22) updates the DOM — reading ref.current inside the render body itself is too early and will see a stale/null value; refs are safe to read in event handlers and Effects, which run after commit.
  • Best practices: use refs only for interactions React doesn't model declaratively (focus management, media playback control, text selection, scroll position, size/position measurement, non-React widget integration) — never use a ref to read-then-manually-mutate a DOM node's content/attributes that React itself is also managing, since the two will fight and produce inconsistent results.

Code Examples

function SearchInput() {
  const inputRef = useRef(null);
  return (
    <>
      <input ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>Focus</button>
    </>
  );
}
  • What it demonstrates: the canonical ref use case — imperatively calling .focus() on a real DOM node in response to a click, something no declarative prop expresses.

Key Takeaways

  1. Reserve DOM refs for genuinely imperative browser APIs (focus, scroll, media, measurement) — if a change can be expressed as JSX/props instead, prefer that.
  2. Never manually mutate a DOM node's attributes/content that React also renders via that same node — the two will conflict on the next render.
  3. A ref only reliably points at the mounted node after commit — access it from event handlers or Effects, never mid-render.

Connects To

  • Ch 34 (Referencing Values with Refs): the general-purpose ref mechanic this chapter specializes to DOM nodes.
  • Ch 22 (Render and Commit): the commit step that must complete before a ref's DOM node is available.
  • Ch 91 (use) and Ch 85 (forwardRef): the modern and legacy ways a custom component exposes its DOM node to a parent's ref.