useLayoutEffect Hook — Synchronous DOM Updates Before Rendering
useLayoutEffect is a React hook that is very similar to useEffect, but it runs synchronously immediately after render and before DOM repaint. This means it executes at the moment when React has already updated the DOM, but hasn't yet "displayed" it to the user.
This means you can safely measure DOM dimensions, scroll position, or prepare layout animations without visible flickering to the user.
🔹 Difference Between useEffect and useLayoutEffect
| useEffect | useLayoutEffect |
|---|---|
| Asynchronous: runs after render when DOM is already visible. | Synchronous: runs immediately after render but before repaint. |
| Suitable for side effects (fetch, event, subscription). | Suitable for layout effects (DOM measurement, scroll, animation). |
| Doesn't block UI rendering. | Can block rendering if there are heavy computations. |
📍 Example 1 — DOM Dimension Calculation After Render
When you want to know an element's height or width, the right time is useLayoutEffect. If you do the same with useEffect, it might calculate the already visible DOM, causing flickering.
import React, { useRef, useLayoutEffect, useState } from 'react';
export default function BoxMeasure() {
const boxRef = useRef();
const [boxHeight, setBoxHeight] = useState(0);
useLayoutEffect(() => {
const height = boxRef.current.getBoundingClientRect().height;
setBoxHeight(height);
}, []);
return (
<div>
<div
ref={boxRef}
style={{ width: '200px', height: '150px', background: '#61dafb', marginBottom: '10px' }}
></div>
<p>Block height: {boxHeight}px</p>
</div>
);
}
Here `useLayoutEffect` allows correctly measuring DOM dimensions before React paints it to the screen. If you did the same with `useEffect`, you would first see "0px" and then the update.
📍 Example 2 — Scroll Position Control
If you want to restore scroll position immediately after render, you should use `useLayoutEffect` because scrolling should occur before repaint.
import React, { useLayoutEffect } from 'react';
export default function ScrollTop() {
useLayoutEffect(() => {
window.scrollTo(0, 0);
}, []);
return (
<div style={{ height: '200vh', background: 'linear-gradient(#fff, #ccc)' }}>
<h2>Page scrolls to top immediately after render</h2>
</div>
);
}
With this example, the page scrolls immediately after render without visible movement.
📍 Example 3 — Layout Animation (DOM Reposition)
When you need to reposition multiple DOM elements or create animations, you can use useLayoutEffect to measure previous and current positions.
import React, { useState, useLayoutEffect, useRef } from 'react';
export default function AnimatedBox() {
const [toggle, setToggle] = useState(false);
const boxRef = useRef();
useLayoutEffect(() => {
const box = boxRef.current;
box.style.transition = 'none';
box.style.transform = 'scale(0.5)';
requestAnimationFrame(() => {
box.style.transition = 'transform 0.4s ease';
box.style.transform = 'scale(1)';
});
}, [toggle]);
return (
<div>
<button onClick={() => setToggle(t => !t)}>Change Position</button>
<div
ref={boxRef}
style={{
marginTop: '20px',
width: '100px',
height: '100px',
background: toggle ? '#4caf50' : '#ff5722',
}}
></div>
</div>
);
}
This example uses `useLayoutEffect` to ensure smooth animation without "flicker". If you did the same with `useEffect`, React would render the transitional state.
⚙️ When to Use useLayoutEffect
- When you need to measure or change DOM immediately after render.
- When UI needs to be precisely synchronized (e.g., scroll, animation, reposition).
- When you want to prevent visible changes to the user's eye.
🚫 When Not to Use useLayoutEffect
- When the effect is heavy or async — can block UI.
- When the operation can be done with `useEffect` — always prefer it.
- During server-side rendering (SSR), React will complain if used without client check.
For SSR, use:
if (typeof window !== 'undefined') { useLayoutEffect(...); }
🎯 Exercise (Try it yourself)
Write a component that:
- Has a div block whose height is calculated via useLayoutEffect.
- Displays that height immediately after render.
- If you use useEffect, "flicker" should be noticeable — try the difference.
📘 Summary
- useLayoutEffect — works synchronously immediately after render and before repaint.
- Suitable for DOM measurements, scroll, and animations.
- Avoid heavy computations — can slow down UI.
- If you don't need to control layout, use useEffect for performance.