useLayoutEffect
useLayoutEffect
useLayoutEffect is a React Hook that is identical in signature to useEffect, but it fires synchronously before the browser repaints the screen.
Syntax
useLayoutEffect(setup, dependencies?)
useEffect vs useLayoutEffect
To understand why useLayoutEffect exists, you need to understand the timing of useEffect:
- React renders your component.
- The browser paints the screen (the user sees the UI).
useEffectruns. (Asynchronous)
If your Effect mutates the DOM (e.g., measuring an element’s height and then immediately changing its style based on that measurement), the user will see a visible “flicker”. They will see the initial paint, and then a split-second later, they will see the DOM mutate again.
The timing of useLayoutEffect prevents this flicker:
- React renders your component.
useLayoutEffectruns. (Synchronous)- React waits for your
useLayoutEffectto finish. If you update state inside it, React re-renders the component immediately. - The browser paints the screen (the user sees the final UI).
Example: Tooltip Positioning
A classic use case is a Tooltip that needs to measure its own dimensions to decide whether to render above or below a button.
function Tooltip({ children, targetRect }) {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0);
// We use useLayoutEffect because we need to measure the DOM node
// before the browser actually paints it to the screen.
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height);
}, []); // Runs once right after the DOM is constructed, but before paint
let tooltipY = 0;
if (targetRect !== null) {
tooltipY = targetRect.bottom;
if (tooltipY + tooltipHeight > window.innerHeight) {
// It doesn't fit below, put it above
tooltipY = targetRect.top - tooltipHeight;
}
}
return (
<div ref={ref} style={{ top: tooltipY }}>
{children}
</div>
);
}
Performance Warning
Because useLayoutEffect runs synchronously and blocks the browser from painting, it can hurt performance if overused. Your app will feel sluggish if you do expensive calculations inside it.
Rule of thumb: Always start with useEffect. Only switch to useLayoutEffect if you notice a visible UI flicker caused by your DOM mutations.
Interview Questions
Q: What is the core difference between useEffect and useLayoutEffect?
A: useEffect runs asynchronously after the browser has painted the DOM. useLayoutEffect runs synchronously before the browser paints the screen, literally blocking the paint.
Q: When should you reach for useLayoutEffect?
A: Almost never, unless you are measuring DOM nodes (like calculating a tooltip’s width) and need to immediately reposition an element before the user sees it, avoiding a visual flicker.