
useLayoutEffect vs useEffect
Both hooks run after render, but at different times. The timing difference matters for DOM measurements and avoiding visual flicker.
Timing
Render → DOM mutations (commit) → useLayoutEffect → Browser paint → useEffect useLayoutEffectfires synchronously after DOM mutations, before the browser paintsuseEffectfires asynchronously after the browser paints
useLayoutEffect for Measurements
function Tooltip({ targetRef, content }) {
const tooltipRef = useRef(null);
const [position, setPosition] = useState({ top: 0, left: 0 });
useLayoutEffect(() => {
const targetRect = targetRef.current.getBoundingClientRect();
const tooltipRect = tooltipRef.current.getBoundingClientRect();
setPosition({
top: targetRect.bottom + 8,
left: targetRect.left - tooltipRect.width / 2,
});
}, []);
return (
<div ref={tooltipRef} style={position}>
{content}
</div>
);
} With useEffect, the tooltip briefly renders at {top: 0, left: 0} before snapping to position — a visible flash. With useLayoutEffect, the position is computed and applied before paint.
When to Use Which
useEffect (default for almost everything):
- Data fetching
- Subscriptions
- Analytics, logging
- Any side effect that doesn’t need to block paint
useLayoutEffect (only when needed):
- Reading DOM layout (
getBoundingClientRect,scrollHeight,offsetWidth) - Synchronously re-positioning or resizing elements based on measurements
- Preventing visual flicker from layout calculations
SSR Warning
useLayoutEffect doesn’t run during SSR. React warns:
Warning: useLayoutEffect does nothing on the server Suppress safely with an isomorphic hook:
const useIsomorphicLayoutEffect =
typeof window === 'undefined' ? useEffect : useLayoutEffect; Don’t Overuse
useLayoutEffect blocks the browser from painting until it completes. Heavy work inside it causes jank. Keep it focused on DOM reads and minimal, targeted writes.









