Cansu Arı Logo
Blog
What is it?

useEffect or useLayoutEffect? The Battle of Milliseconds

The difference isn’t just timing; it’s a critical detail for UX, performance, and visual smoothness.

  • #React
  • #Performance

Skip to content

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

HookWhen it runsPrimary purpose
useLayoutEffectRight after the DOM is updated, before the browser paintsDOM measurements, synchronous layout tweaks, kicking off animations
useEffectAfter the browser has paintedData fetching, adding event listeners, persisting state
TL;DR: useLayoutEffect fires just before paint. useEffect fires after paint. That tiny gap prevents flicker and layout jumps.

Timing chain

React’s render pipeline:

  1. Render phase: React computes the virtual DOM.
  2. Commit phase: The real DOM is updated.
  3. Layout Effect phase: useLayoutEffect runs—DOM is updated, but nothing painted yet.
  4. Paint phase: The browser paints to screen.
  5. Effect phase: useEffect runs—user already sees the UI.
This ordering is crucial for measurement and animation accuracy.

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?

ScenarioCorrect hook
Fetching from an APIuseEffect
Adding/removing event listenersuseEffect
localStorage/analytics side effectsuseEffect
Measuring or manipulating the DOMuseLayoutEffect
Positioning tooltips/modalsuseLayoutEffect
Starting CSS/JS animationsuseLayoutEffect
Visual alignment fixesuseLayoutEffect
Rule of thumb: If you touch layout (measure/position/mutate), use 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

  • useLayoutEffect is synchronous and blocks paint. Heavy work here will freeze the UI—keep it minimal.
  • In SSR, useLayoutEffect warns because there’s no layout on the server.
Solution:
import { useLayoutEffect, useEffect } from 'react';
const useIsomorphicEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
  • Overusing useLayoutEffect harms 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:

useInsertionEffectuseLayoutEffect → 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.
In short: 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.
All tags
  • React
  • Performance