When should you use useLayoutEffect?
Short version: why it exists
useLayoutEffect() is a version of useEffect()
that runs right after React has updated the DOM,
but before the browser paints the changes on the screen.
That is, it gives you the ability to:
measure or change the DOM before the user sees it.
Use useLayoutEffect when you need to:
1. Measure the DOM before it paints
If you want to get exact dimensions or the position of an element
(for example, to calculate the position of a popup, a tooltip, a caret, etc.),
use useLayoutEffect so the browser doesn't get a chance to paint the "old" state.
function Tooltip({ text }) {
const ref = useRef(null);
useLayoutEffect(() => {
const { width, height } = ref.current.getBoundingClientRect();
console.log("Element size before display:", width, height);
}, []);
return <div ref={ref}>{text}</div>;
}Why not useEffect:
in useEffect the measurements happen after the paint,
and the data can already be stale (or cause a "jump").
2. Synchronize visual state with the DOM
If you manually change the DOM (for example, positioning, scrolling, or applying an animation),
and you don't want the user to see an intermediate state,
do it in useLayoutEffect.
useLayoutEffect(() => {
elementRef.current.scrollTop = elementRef.current.scrollHeight;
}, [messages]);This way the scroll happens before the content is displayed, and there is no visual "jump".
3. Prevent a "flicker" or "jump" in the interface
Sometimes, when a component loads, you change sizes, positions, classes, etc.
If you do this via useEffect, React shows the old UI first,
then "rebuilds" it, and the user sees a "flash".
Using useLayoutEffect solves this:
useLayoutEffect(() => {
ref.current.style.transform = "translateY(50px)";
}, []);The effect is applied before paint, and the user sees the final look right away.
4. Animation synchronization
If you work with animation libraries (Framer Motion, GSAP, Anime.js, etc.)
and need an animation to start at the exact moment before the paint,
useLayoutEffect gives you that precision.
useLayoutEffect(() => {
gsap.from(ref.current, { opacity: 0, y: -20, duration: 0.3 });
}, []);5. When logic depends on an immediate DOM update
Sometimes you change state and must read up-to-date sizes/positions right after.
useEffect would be too late, because the browser has already "shown" the old state.
Example: computing a block's height when state changes:
useLayoutEffect(() => {
const h = ref.current.offsetHeight;
console.log("Current height:", h);
}, [isOpen]);When you should NOT use useLayoutEffect
| Case | Why it's bad |
|---|---|
| For API requests, timers, logs | Blocks painting for no reason |
| For logic not related to the DOM | Makes no sense |
| A frequently updating effect | Slows down FPS - React waits for every layout effect to finish |
| During SSR (Next.js, etc.) | React shows a warning: "useLayoutEffect does nothing on the server" |
The ideal rule:
Use
useLayoutEffectonly for DOM operations that need to run before the user sees the screen. Everything else goes inuseEffect.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.