Both hooks run after React updates the DOM. The difference is when they run relative to the browser paint.
One-sentence answer: use useEffect for most side effects; use useLayoutEffect only when you need to read or change layout before the user sees the screen.
Why it matters
Wrong timing shows up as flicker: a modal jumps, a tooltip measures the wrong size, or a scroll position resets after paint. Knowing which hook to use keeps UI stable without overusing the more expensive layout path.
Timing in plain words
- React renders
- React commits DOM updates
useLayoutEffectruns (still before paint)- Browser paints
useEffectruns (after paint)
So the user already sees the UI when useEffect fires. With useLayoutEffect, they don’t see the intermediate state if you fix layout in that window.
When to use useEffect
Use it for work that can wait until after paint:
- Fetching data
- Adding event listeners or subscriptions
- Analytics / logging
- Syncing with external stores
useEffect(() => {
const controller = new AbortController();
fetch("/api/profile", { signal: controller.signal })
.then((res) => res.json())
.then(setProfile);
return () => controller.abort();
}, []);When to use useLayoutEffect
Use it when skipping paint would cause a visible glitch:
- Measuring DOM (
getBoundingClientRect,offsetHeight) - Restoring or locking scroll position
- Positioning a popover/tooltip from measured coords
- Avoiding a flash of wrong styles or layout
useLayoutEffect(() => {
if (!ref.current) return;
const { height } = ref.current.getBoundingClientRect();
setMeasuredHeight(height);
}, [content]);Common mistakes
- Using
useLayoutEffectfor data fetching (blocks paint for no benefit) - Forgetting cleanup (listeners, observers, abort controllers)
- Assuming layout effects are “faster” — they can make interactions feel slower if overused
- Ignoring SSR:
useLayoutEffectwarns on the server; guard or preferuseEffectfor client-only measurement patterns when needed
When not to use useLayoutEffect
If the UI looks fine with useEffect, keep it. Don’t “upgrade” to layout effects by default.
Takeaway
Start with useEffect. Switch to useLayoutEffect only when you must measure or adjust the DOM before the browser paints — usually to prevent flicker.