0
0
ReactComparisonBeginner · 4 min read

UseEffect vs useLayoutEffect: Key Differences and When to Use Each

useEffect runs after the browser paints the screen, making it ideal for side effects that don't block rendering. useLayoutEffect runs synchronously before the browser paints, useful for DOM measurements or updates that must happen before the user sees the UI.
⚖️

Quick Comparison

Here is a quick side-by-side comparison of useEffect and useLayoutEffect to understand their main differences.

FactoruseEffectuseLayoutEffect
Execution TimingAfter browser paintBefore browser paint
Blocking UIDoes not block UI renderingBlocks UI rendering until effect finishes
Use CaseSide effects like data fetching, subscriptionsDOM measurements, synchronously updating layout
Performance ImpactBetter for non-blocking tasksCan cause layout thrashing if overused
Common PitfallMay cause flicker if updating layoutCan delay paint causing jank if heavy work
⚖️

Key Differences

useEffect runs its effect function after the browser has painted the UI. This means it does not block the user from seeing the initial render. It is perfect for side effects like fetching data, setting up subscriptions, or logging, where you don't need to block the UI.

In contrast, useLayoutEffect runs synchronously immediately after React has performed all DOM mutations but before the browser paints. This lets you read layout from the DOM and synchronously re-render if needed, preventing visual glitches. However, because it blocks painting, heavy work here can cause noticeable delays.

Choosing between them depends on whether your effect needs to happen before the user sees the UI (useLayoutEffect) or can happen after without blocking rendering (useEffect).

⚖️

Code Comparison

This example uses useEffect to update the document title after the component renders.

javascript
import React, { useEffect, useState } from 'react';

function TitleUpdater() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);

  return (
    <div>
      <p>Count is {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default TitleUpdater;
Output
A button and text showing count; document title updates after render to 'Count: X' where X is count.
↔️

useLayoutEffect Equivalent

This example uses useLayoutEffect to measure a DOM element's width before the browser paints, ensuring layout updates happen synchronously.

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

function WidthMeasurer() {
  const ref = useRef(null);
  const [width, setWidth] = useState(0);

  useLayoutEffect(() => {
    if (ref.current) {
      setWidth(ref.current.getBoundingClientRect().width);
    }
  }, []);

  return (
    <div>
      <div ref={ref} style={{ width: '50%' }}>Resize the window</div>
      <p>Measured width: {width}px</p>
    </div>
  );
}

export default WidthMeasurer;
Output
A div sized at 50% width and a paragraph showing its measured width in pixels, updated before paint.
🎯

When to Use Which

Choose useEffect when your side effect does not need to block the browser paint, such as fetching data, event listeners, or logging. It keeps your app responsive and avoids blocking UI updates.

Choose useLayoutEffect when you need to read or modify the DOM layout synchronously before the user sees it, like measuring element sizes or synchronously applying styles to prevent flicker.

In general, prefer useEffect for most cases and only use useLayoutEffect when you must avoid visual glitches caused by layout changes.

Key Takeaways

useEffect runs after paint and is best for non-blocking side effects.
useLayoutEffect runs before paint and is for DOM reads or synchronous layout updates.
Use useEffect by default and switch to useLayoutEffect only to prevent flicker or layout glitches.
useLayoutEffect can block rendering and cause jank if overused.
Choosing the right hook improves UI responsiveness and visual stability.