βοΈ React Hook: useLayoutEffect
β
π Quick Summary β
useLayoutEffect
is similar touseEffect
, but it runs synchronously after all DOM mutations and before the browser paints.- Use it when you need to read layout values or synchronously re-render before the browser updates the screen.
- Syntax:tsx
useLayoutEffect(() => { // effect code return () => { // optional cleanup }; }, [dependencies]);
π§ Mental Model β
- Think of
useEffect
as running after painting π¨ (async, non-blocking). - Think of
useLayoutEffect
as running before painting π (blocking). - Use it only when the DOM measurement or mutation must be done before the browser visually updates.
π Key Concepts β
Execution Timing
useLayoutEffect
fires synchronously after DOM updates but before paint.useEffect
fires asynchronously after paint.
When to Use
- Measuring DOM nodes (width, height, position).
- Mutating DOM styles synchronously.
- Avoiding flicker by making adjustments before the user sees the UI.
Cleanup
- Same as
useEffect
, cleanup runs before next effect or component unmount.
- Same as
Performance Warning
- Blocks the paint process β overuse may cause performance issues.
π» Code Examples β
Example 1: Basic Usage (DOM measurement) β
import { useLayoutEffect, useRef } from "react";
export default function Box() {
const boxRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
if (boxRef.current) {
console.log("Box width:", boxRef.current.getBoundingClientRect().width);
}
}, []);
return <div ref={boxRef} style={{ width: "200px", height: "100px", background: "skyblue" }}>Box</div>;
}
How it works (stepβbyβstep):
- React renders the
<div>
and commits it to the DOM. - Before the browser paints,
useLayoutEffect
runs synchronously. - We read measurements (
getBoundingClientRect
) while layout is upβtoβdate. - The browser then paints, ensuring no visible flicker between measurement and paint.
Example 2: Avoiding Flicker (synchronous style tweak) β
import { useState, useLayoutEffect } from "react";
export default function FlickerExample() {
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
// synchronously adjust width before paint
setWidth(window.innerWidth / 2);
}, []);
return <div style={{ width, background: "lightcoral" }}>Width adjusted before paint</div>;
}
How it works (stepβbyβstep):
- Initial render sets
width = 0
. useLayoutEffect
runs before paint and updateswidth
towindow.innerWidth / 2
.- React immediately re-renders synchronously with the new width.
- The user only ever sees the final width β no flashing/flicker.
Example 3: Comparing useEffect
vs useLayoutEffect
β
import { useEffect, useLayoutEffect } from "react";
export default function Comparison() {
useEffect(() => {
console.log("useEffect: runs after paint");
});
useLayoutEffect(() => {
console.log("useLayoutEffect: runs before paint");
});
return <p>Check console logs</p>;
}
How it works (stepβbyβstep):
- Component renders and commits to the DOM.
useLayoutEffect
logs first (before the browser paints).- Browser paints the UI.
useEffect
logs after paint.
β οΈ Common Pitfalls & Gotchas β
- β Overusing
useLayoutEffect
β blocks painting, can cause jank. - β Using it when
useEffect
is enough. - β Forgetting cleanup when adding DOM listeners or styles.
β Best Practices β
- Prefer
useEffect
for most side effects. - Use
useLayoutEffect
only when DOM measurements/updates must happen before paint. - Keep logic inside
useLayoutEffect
minimal to avoid blocking rendering. - Clean up listeners/timers to avoid memory leaks.
β Interview Q&A β
Q1. Difference between useEffect
and useLayoutEffect
?
A:
useEffect
β runs asynchronously after paint (non-blocking).useLayoutEffect
β runs synchronously before paint (blocking).
Q2. When should you use useLayoutEffect
?
A: For reading layout (DOM size/position) or synchronously applying style changes before the browser repaints.
Q3. What happens if you overuse useLayoutEffect
?
A: It delays painting β poor performance and laggy UI.
Q4. Can you use multiple useLayoutEffect
hooks in one component?
A: Yes, just like useEffect
. They run in the order they are declared.
Q5. Is useLayoutEffect
SSR-friendly?
A: No. On the server, React will warn you to use useEffect
instead because layout-related APIs (like getBoundingClientRect
) are not available on the server.