When it comes to UX, milliseconds matter.
In React there are two sibling Hooks: useEffect and useLayoutEffect. Both manage effects, but their timing sets them worlds apart. That timing difference is measured in milliseconds—yet it’s huge for perceived quality.
In short: one steps on stage before the lights come on, the other works backstage. Knowing when each runs is the key to performance-friendly React apps.
Core difference
| Hook | When it runs | Primary purpose |
|---|---|---|
| useLayoutEffect | Right after the DOM is updated, before the browser paints | DOM measurements, synchronous layout tweaks, kicking off animations |
| useEffect | After the browser has painted | Data fetching, adding event listeners, persisting state |
useLayoutEffect fires just before paint. useEffect fires after paint. That tiny gap prevents flicker and layout jumps.Timing chain
React’s render pipeline:
- Render phase: React computes the virtual DOM.
- Commit phase: The real DOM is updated.
- Layout Effect phase:
useLayoutEffectruns—DOM is updated, but nothing painted yet. - Paint phase: The browser paints to screen.
- Effect phase:
useEffectruns—user already sees the UI.
Observe in the console
function Example() {
useLayoutEffect(() => console.log('LayoutEffect'));
useEffect(() => console.log('Effect'));
console.log('Render');
return <div>Hello</div>;
}
Console output:
Render
LayoutEffect
Effect
So
useLayoutEffect runs before useEffect.Read it in code
useLayoutEffect(() => {
console.log('LayoutEffect: DOM ready, before paint!');
});
useEffect(() => {
console.log('Effect: Painted, background tasks now!');
});
useLayoutEffect runs as soon as the DOM is committed; useEffect runs after the screen updates.
Real scenario: DOM measurement
const boxRef = useRef();
useLayoutEffect(() => {
const { height } = boxRef.current.getBoundingClientRect();
console.log('Box height:', height);
});
If this were in useEffect, the user could see a one-frame old layout (a flicker) before the adjustment. useLayoutEffect eliminates that.
Which one to choose?
| Scenario | Correct hook |
|---|---|
| Fetching from an API | useEffect |
| Adding/removing event listeners | useEffect |
| localStorage/analytics side effects | useEffect |
| Measuring or manipulating the DOM | useLayoutEffect |
| Positioning tooltips/modals | useLayoutEffect |
| Starting CSS/JS animations | useLayoutEffect |
| Visual alignment fixes | useLayoutEffect |
useLayoutEffect. Otherwise, prefer useEffect.Mini example: measuring before animation
useEffect(() => {
const height = ref.current.offsetHeight;
startAnimation(height); // ❌ Too late for a perfect first frame
}, []);
Better:
useLayoutEffect(() => {
const height = ref.current.offsetHeight;
startAnimation(height); // ✅ Perfectly timed pre-paint
}, []);
⚠️ Caveats
useLayoutEffectis synchronous and blocks paint. Heavy work here will freeze the UI—keep it minimal.- In SSR,
useLayoutEffectwarns because there’s no layout on the server.
import { useLayoutEffect, useEffect } from 'react';
const useIsomorphicEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
- Overusing
useLayoutEffectharms performance. Don’t make everything sync.
Performance and React 18+
With Concurrent Rendering, React schedules sync effects better—but you still must avoid blocking work.
💡 Tip: Pair useLayoutEffect with requestAnimationFrame for silky animations.
Bonus: useInsertionEffect
React 18 introduced useInsertionEffect, which runs even earlier than layout effects—mostly for CSS-in-JS libraries to inject styles.
Order:
useInsertionEffect → useLayoutEffect → paint → useEffect
Real-world example
Opening a modal while blurring/dimming the background: with useEffect, users may see the modal first and the backdrop effect a tick later. With useLayoutEffect, both happen in sync—feels premium. 💅
Conclusion
useEffect→ Do background work after the user sees the UI.useLayoutEffect→ Prepare/measure/tweak the DOM before it’s painted.
useEffect works backstage; useLayoutEffect straightens the curtain before showtime. Choosing correctly boosts performance and perceived quality. In React, timing is the invisible hero of UX.