What’s the difference between useEffect and useLayoutEffect? When does it matter?

LowHardReact
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

Explain the timing difference between useEffect and useLayoutEffect in the render/commit/paint pipeline, why useLayoutEffect blocks painting, and when it is required (DOM measurements, preventing visual flicker) versus when useEffect is preferred.

Answer

Short answer

useEffect runs after the browser paints. useLayoutEffect runs synchronously after DOM mutations but before the browser paints. The difference matters when you need to read or write layout and avoid visual flicker.

The render pipeline (mental model)

Roughly, React does this:

1) Render (compute virtual tree)
2) Commit (apply DOM changes)
3) useLayoutEffect runs here (before paint)
4) Browser paints to screen
5) useEffect runs here (after paint)

Hook

When it runs

Does it block paint?

useLayoutEffect

After DOM updates, before paint

✅ Yes (blocks paint)

useEffect

After paint

❌ No (non-blocking)

The critical timing difference

Why this difference exists

useLayoutEffect exists for code that must synchronously read or modify the DOM before the user sees anything. useEffect is for everything else (data fetching, subscriptions, logging, timers, etc.).

JSX
function Example() {
  const ref = useRef(null);

  useLayoutEffect(() => {
    const rect = ref.current.getBoundingClientRect();
    // Measure and synchronously adjust layout
  }, []);

  return <div ref={ref}>Hello</div>;
}
                  

What happens if you use useEffect for layout work?

The browser will:
• Paint the UI once
• Then your effect runs
• Then you update layout/state
• Then it paints again

The user sees a visual flicker / jump.

JSX
function Tooltip({ text }) {
  const ref = useRef(null);
  const [top, setTop] = useState(0);

  // ❌ This can cause visible jump
  useEffect(() => {
    const rect = ref.current.getBoundingClientRect();
    setTop(rect.top - 10);
  }, []);

  return (
    <div ref={ref} style={{ position: 'absolute', top }}>
      {text}
    </div>
  );
}
                  

Correct version:

JSX
useLayoutEffect(() => {
  const rect = ref.current.getBoundingClientRect();
  setTop(rect.top - 10);
}, []);
// ✅ User never sees the wrong position
                  

When you should use useLayoutEffect

Scenario

Why

Examples

Measuring DOM size/position

Must read layout before paint

getBoundingClientRect, offsetWidth

Synchronously adjusting layout

Prevent visible jumps

Tooltips, popovers, modals

Scroll position corrections

Avoid one-frame wrong scroll

Scroll restoration, anchored lists

Imperative animations setup

Need correct initial layout

FLIP animations, measurement-based motion

Legitimate use cases for useLayoutEffect

When you should use useEffect (almost always)

• Data fetching
• Subscriptions / event listeners
• Logging / analytics
• Timers
• Syncing with external systems

These do not need to block paint and should not slow down rendering.

Why you should avoid overusing useLayoutEffect

Because it blocks the browser from painting. Too many or heavy useLayoutEffect calls = slow first paint and janky UI.

SSR warning

useLayoutEffect does nothing on the server and causes warnings in SSR environments. Many frameworks alias it to useEffect on the server. Another reason to only use it when truly necessary.

Rule of thumb

Start with useEffect. Only switch to useLayoutEffect if you see a visual flicker, layout jump, or need to measure/mutate layout before paint.

Interview framing

Say it like this:
"useLayoutEffect runs synchronously after DOM mutations but before paint and blocks rendering, so it’s for layout measurement and visual correctness. useEffect runs after paint and is non-blocking, so it’s for side effects like data fetching and subscriptions. You should prefer useEffect unless you need to prevent visual flicker."

Summary

useLayoutEffect runs before the browser paints and blocks rendering, making it suitable for DOM measurements and layout corrections. useEffect runs after paint and should be used for most side effects. Overusing useLayoutEffect hurts performance, so only use it when visual correctness requires it.

Similar questions
Guides
40 / 41