React useLayoutEffect: Synchronous DOM Measurement & Flicker Prevention

While 99% of side effects should use useEffect (because it does not block the browser paint), there are specialized cases where an effect needs to read element dimensions and adjust styles before the user sees the screen. If done with useEffect, users will notice an annoying visual flicker or layout jump. The useLayoutEffect hook executes synchronously to prevent this flicker.

Execution Order Comparison: useEffect vs useLayoutEffect

  1. React updates Virtual DOM and applies mutations to the real DOM nodes.
  2. useLayoutEffect fires synchronously! You can read layout (e.g. getBoundingClientRect()) and update state.
  3. Browser paints the updated DOM pixels onto the physical display.
  4. useEffect fires asynchronously! Data fetching, subscriptions, and non-blocking tasks run.

Practical Example: Measuring Tooltip Dimensions Before Paint

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

function Tooltip({ targetElement, text }) {
  const [tooltipHeight, setTooltipHeight] = useState(0);
  const tooltipRef = useRef(null);

  // Runs synchronously before the browser paints! Prevents visual reposition jump
  useLayoutEffect(() => {
    if (tooltipRef.current) {
      const { height } = tooltipRef.current.getBoundingClientRect();
      setTooltipHeight(height);
    }
  }, []);

  return (
    <div 
      ref={tooltipRef}
      style={{
        position: 'absolute',
        top: -tooltipHeight - 10, // Places tooltip perfectly above button
        background: '#0f172a',
        color: '#fff',
        padding: '6px 12px',
        borderRadius: '4px',
        fontSize: '12px'
      }}
    >
      {text}
    </div>
  );
}

Next Step: useImperativeHandle & forwardRef

Now let us step into advanced parent-child imperative controls in React useImperativeHandle & forwardRef.

Explore Related React JS Tutorials

Accelerate your React mastery by studying these tightly connected core tutorials:

useEffect vs useLayoutEffect →

Asynchronous post-paint vs synchronous pre-paint.

Measuring DOM Nodes (getBoundingClientRect) →

Calculating element dimensions before flicker.

Commit Phase Mutation →

Where layout effects hook into the browser painting pipeline.

Share Share on Facebook Share on Twitter Share on LinkedIn Pin on Pinterest Share on Stumbleupon Share on Tumblr Share on Reddit Share on Diggit

You may also like this!