Capítulo 58 de 116

Chapter 58: useLayoutEffect

Core Idea

useLayoutEffect(setup, dependencies?) fires synchronously after DOM mutations but before the browser paints — the tool for reading layout (measuring an element) and then synchronously adjusting it before the user ever sees the unadjusted version.

Key Concepts

  • Same signature/shape as useEffect (setup function, optional cleanup, dependency array with identical semantics) — the difference is purely timing.
  • Timing: runs after React updates the DOM but before the browser paints that update to the screen — this blocks visual updates until it finishes, unlike useEffect, which runs after paint and doesn't block it.
  • When it's actually needed: measuring a DOM element (its size/position) and then synchronously repositioning something based on that measurement — e.g. a tooltip that needs to flip position to avoid clipping. If the adjustment happened in a regular useEffect, the user would briefly see the un-flipped tooltip flash before the correction, since the browser would have already painted.
  • Performance cost is real: because it blocks paint, an expensive useLayoutEffect body directly slows down perceived responsiveness — use it only when the visible flash it prevents would actually be a problem, not as a default over useEffect.
  • SSR caveat: useLayoutEffect doesn't run during server rendering (there's no browser layout to read) — React warns if it's used in a component that renders on the server without a client-only guard, since its effect would be missing on the server-rendered HTML.

Code Examples

useLayoutEffect(() => {
  const { height } = ref.current.getBoundingClientRect();
  setTooltipHeight(height); // synchronous, before paint — avoids a visible flash
}, []);
  • What it demonstrates: measuring and reacting to layout before the browser paints, preventing a visible flicker that a post-paint useEffect would cause.

Key Takeaways

  1. Default to useEffect; reach for useLayoutEffect only when skipping it would cause a visible flash/flicker from a measure-then-adjust sequence.
  2. It blocks the browser from painting until it finishes — treat that as a real performance cost, not a free upgrade over useEffect.
  3. It doesn't run during server rendering — guard usage accordingly in SSR contexts.

Connects To

  • Ch 53 (useEffect): the default, non-blocking Effect Hook this one trades performance for timing guarantees against.
  • Ch 57 (useInsertionEffect): the even-earlier Hook in the same commit-phase sequence.
  • Ch 35 (Manipulating the DOM with Refs): the DOM-measurement use case this Hook typically pairs with.