Part 22: useLayoutEffect Hook: Synchronous DOM Updates & Measurements

Part 22 Technology Updated September 12, 2026

Part 22: useLayoutEffect Hook: Synchronous DOM Updates & Measurements

useLayoutEffect is identical to useEffect in signature, but it fires synchronously after all DOM mutations, before the browser paints pixels to the screen.


1. The Rendering Lifecycle: useEffect vs useLayoutEffect

[ State / Props Change ]
           │
           ▼
[ React renders JSX & updates Virtual DOM ]
           │
           ▼
[ React mutates Real DOM nodes ]
           │
           ├──► [ useLayoutEffect runs SYNCHRONOUSLY ] (Blocks Paint)
           │
           ▼
[ Browser Paints Screen (User sees new UI) ]
           │
           ├──► [ useEffect runs ASYNCHRONOUSLY ] (Does NOT Block Paint)

2. When to Use useLayoutEffect

Use useLayoutEffect when you need to: 1. Measure DOM elements (e.g., width, height, scroll position). 2. Apply DOM adjustments based on those measurements before the browser paints, preventing visual flickering.

Real-World Example: Tooltip Positioning

import { useState, useRef, useLayoutEffect } from 'react';

export default function Tooltip({ targetRect, text }) {
  const tooltipRef = useRef(null);
  const [coords, setCoords] = useState({ top: 0, left: 0 });

  useLayoutEffect(() => {
    if (tooltipRef.current) {
      const tooltipHeight = tooltipRef.current.offsetHeight;
      // Position tooltip right above target without visual flicker
      setCoords({
        top: targetRect.top - tooltipHeight - 8,
        left: targetRect.left
      });
    }
  }, [targetRect]);

  return (
    <div
      ref={tooltipRef}
      style={{ position: 'fixed', top: coords.top, left: coords.left }}
      className="bg-black text-white px-2 py-1 rounded text-xs"
    >
      {text}
    </div>
  );
}

Key Takeaways

  • useEffect is non-blocking and preferred for 99% of side effects (data fetching, timers).
  • useLayoutEffect runs synchronously before paint and is reserved for layout measurements to prevent visual flickers.

In Part 23, we explore advanced hooks: useId and useImperativeHandle!