Both run effects, but at different moments relative to the browser paint — and that timing difference is the whole point.
Both run effects, but at different moments relative to the browser paint — and that timing difference is the whole point.
useEffect runs after the browser has painted. It's asynchronous and non-blocking. Use it for almost everything (data, subscriptions, logging).useLayoutEffect runs synchronously after the DOM is mutated but BEFORE the browser paints. Use it when you must read layout and change the DOM in the same frame to avoid a visible flicker.render → DOM updated → [useLayoutEffect runs] → browser paints → [useEffect runs]
Imagine measuring an element and repositioning a tooltip based on its size. With useEffect, the user would briefly see the tooltip in the wrong spot, then it jumps:
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipTop(-height); // applied BEFORE paint → no visible jump
}, []);
With useEffect, the same code runs after paint → a one-frame flicker.
useLayoutEffect makes the UI feel janky, because the browser can't paint until it finishes.Rule of thumb: default to useEffect; only use useLayoutEffect for synchronous DOM measurements/mutations that would otherwise flicker.
A library of IT interview questions with detailed answers — from Junior to Senior.
Donate