useLayoutEffect vs useEffect
useLayoutEffect is a React Hook that runs synchronously after the DOM is updated but before the browser paints, whereas useEffect runs asynchronously after paint. You reach for useLayoutEffect only when you must measure layout and adjust it before the user sees a flicker.
Learn useLayoutEffect vs useEffect in our free React course — an interactive lesson with runnable examples, a practice exercise and a quick recall.
Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
1️⃣ The Timing Difference
After a render, React mutates the DOM. Then useLayoutEffect fires synchronously, before the browser paints — so any DOM change you make is included in the very first frame the user sees. The browser paints, and only then does useEffect fire asynchronously , after paint. That single ordering difference is the whole lesson.
2️⃣ Measuring Layout & Avoiding Flicker
The classic use case is reading a DOM measurement (width, height, scroll position) and then immediately changing the layout based on it — like positioning a tooltip above its anchor. If you did this in useEffect , the element would paint in the wrong spot for one frame and then jump, producing a visible flicker . Doing it in useLayoutEffect fixes the position before that first paint.
3️⃣ When NOT to Use It & the SSR Warning
Because useLayoutEffect runs synchronously before paint, heavy work inside it blocks painting and makes the UI feel sluggish. So default to useEffect for data fetching, subscriptions, logging, and anything that does not need to happen before paint. Also, on the server there is no DOM and no paint, so React warns about useLayoutEffect during SSR — use useEffect there, or run the layout effect only on the client.
These steps are the lifecycle of one update with both hooks. Put them in the right order:
📋 Quick Reference
useLayoutEffect — synchronously, after DOM mutation but before the browser paints.
It runs after paint and does not block rendering, keeping the UI responsive. Only measure-and-adjust layout needs pre-paint timing.
There is no DOM or paint on the server, so a layout effect cannot run meaningfully. Use useEffect or a client guard.
Compute where a tooltip's top should sit so it appears above each anchor — the kind of measurement that belongs in a pre-paint effect. Run it and check your output.
Practice quiz
When does useLayoutEffect run relative to the browser paint?
- Asynchronously, after the browser paints
- Before React renders the component
- Synchronously, after DOM mutation but before the browser paints
- Only on the server during SSR
Answer: Synchronously, after DOM mutation but before the browser paints. useLayoutEffect fires synchronously after React mutates the DOM but before paint, so DOM changes appear in the first frame the user sees.
When does useEffect run relative to the browser paint?
- Asynchronously, after the browser paints
- Synchronously, before paint
- During the render phase
- It never runs in the browser
Answer: Asynchronously, after the browser paints. useEffect runs asynchronously after the browser has painted, which keeps the UI responsive and avoids blocking rendering.
Which hook should you reach for to measure the DOM and adjust layout without a visible flicker?
- useEffect
- useMemo
- useCallback
- useLayoutEffect
Answer: useLayoutEffect. Because useLayoutEffect runs before paint, you can measure and synchronously adjust layout so the user never sees the intermediate position.
Why is useEffect the recommended default over useLayoutEffect?
- useEffect can read the DOM but useLayoutEffect cannot
- useLayoutEffect runs synchronously before paint and can block rendering
- useEffect runs more times per render
- useLayoutEffect does not support cleanup functions
Answer: useLayoutEffect runs synchronously before paint and can block rendering. useLayoutEffect blocks painting while it runs. Heavy work there makes the UI sluggish, so default to useEffect unless you must adjust layout pre-paint.
Why does React warn about useLayoutEffect during server-side rendering?
- There is no DOM or paint on the server, so it cannot run meaningfully
- It runs too many times on the server
- It conflicts with useEffect on the server
- It requires a network connection
Answer: There is no DOM or paint on the server, so it cannot run meaningfully. On the server there is no DOM to lay out and no paint, so useLayoutEffect can't do its job. Use useEffect or guard it to run only on the client.
What is the correct order of events for a single update with both hooks?
- render → useEffect → paint → DOM mutation → useLayoutEffect
- useEffect → render → paint → useLayoutEffect → DOM mutation
- render → DOM mutation → useLayoutEffect → paint → useEffect
- paint → render → useLayoutEffect → useEffect → DOM mutation
Answer: render → DOM mutation → useLayoutEffect → paint → useEffect. React renders, mutates the DOM, runs useLayoutEffect (pre-paint), the browser paints, then useEffect runs (post-paint).
Where should you put a data fetch — useEffect or useLayoutEffect?
- useLayoutEffect, so it runs sooner
- useEffect, since fetching doesn't need pre-paint timing and shouldn't block paint
- Either one; there is no difference
- Neither — fetch during render
Answer: useEffect, since fetching doesn't need pre-paint timing and shouldn't block paint. Fetching has no DOM-layout need and blocking paint hurts performance, so it belongs in useEffect (after paint).
What causes a visible 'flicker' when positioning a tooltip?
- Using useLayoutEffect to measure before paint
- Calling the hook at the top level
- Returning a cleanup function
- Measuring and adjusting layout in useEffect, after the first paint
Answer: Measuring and adjusting layout in useEffect, after the first paint. If you measure and move the element in useEffect, it paints in the wrong spot for one frame then jumps. Pre-paint useLayoutEffect avoids that.
Both hooks support which of the following?
- Only useLayoutEffect supports a cleanup function
- Both accept a setup function that can return a cleanup function
- Only useEffect supports a dependency array
- Neither can be given a dependency array
Answer: Both accept a setup function that can return a cleanup function. useEffect and useLayoutEffect share the same signature: a setup function (optionally returning cleanup) plus an optional dependency array.
Because useLayoutEffect runs synchronously before paint, what guidance follows?
- Put as much heavy work in it as possible
- Never return a cleanup function from it
- Keep the work light so it doesn't delay painting
- Always pass an empty dependency array
Answer: Keep the work light so it doesn't delay painting. Anything in useLayoutEffect delays the paint, so keep it small — just the measure-and-adjust work that must happen before the user sees the frame.