Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
useLayoutEffect is just like useEffect, but it runs after React updates the DOM and before the browser paints. That lets you measure layout and fix positions before the user sees anything.
1. React updates DOM
Nodes exist, refs are ready.
2. useLayoutEffect
Measure + synchronously update.
3. Browser paints
User sees the final layout.
"useLayoutEffect is just useEffect that runs faster"
Reality: It's not faster—it blocks the browser from painting! This can actually slow down your app if used unnecessarily.
"When exactly does it run?"
Reality: It runs immediately after React commits to the DOM, but before the browser paints. useEffect runs after painting.
"I need to measure DOM and fix layout before the user sees it"
Perfect! This is exactly what useLayoutEffect is for—preventing visual glitches.
useRef gives you access to DOM elements, and useLayoutEffect lets you measure those elements before the browser paints. Together, they prevent visual flicker!
First, create a ref to hold your DOM element. This is your handle to the actual element in the browser.
Remember useRef
useRef creates a container that holds your DOM element. Start with null for DOM refs.
Connect your ref to the JSX element using the ref attribute. React will automatically put the DOM element in your ref.
React Magic
React automatically puts the DOM element in elementRef.current after mounting!
Now use useLayoutEffect to measure your element and make layout changes before the browser paints.
Safety Check
Always check elementRef.current exists before using it. It's null before mount!
Use the measurements to update styles or positions. This happens synchronously, so the browser paints with your corrections already applied.
No Flicker!
Because this runs before paint, users never see the "wrong" layout. They only see your corrected version!
Prevent tooltip flicker with useLayoutEffect
function TooltipExample() {
const [showTooltip, setShowTooltip] = React.useState(false);
const [position, setPosition] = React.useState({ top: 0, left: 0 });
const buttonRef = React.useRef(null);
// This runs BEFORE the browser paints
React.useLayoutEffect(() => {
if (showTooltip && buttonRef.current) {
// Measure the button position
const buttonRect = buttonRef.current.getBoundingClientRect();
// Calculate tooltip position (exactly under button)
const newTop = buttonRect.bottom + 8; // 8px gap
const newLeft = buttonRect.left + (buttonRect.width / 2); // Center of button
// Update position synchronously BEFORE paint
setPosition({ top: newTop, left: newLeft });
console.log('Layout measured and fixed before paint!');
}
}, [showTooltip]);
return (
<div className="container">
<h2>Hover over the button</h2>
<p>Notice: No visual flicker when tooltip appears!</p>
<div className="button-container">
<button
ref={buttonRef}
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
className="action-button"
>
Hover Me
</button>
{showTooltip && (
<div
className="tooltip"
style={{
position: 'fixed',
top: position.top + 'px',
left: position.left + 'px',
transform: 'translateX(-50%)',
}}
>
I'm perfectly positioned! 🎯
</div>
)}
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<TooltipExample />);Loading preview...
Reading element dimensions, positions, or scroll offsets before paint
Fixing tooltip positions, modal centering, or dynamic layouts
Integrating with libraries that need synchronous DOM updates
Use useEffect instead. Blocking paint for network requests hurts performance.
useEffect is better for subscriptions, timers, and most side effects.
If you don't need layout info, useEffect is always faster.
Runs after DOM updates but before paint. Perfect for preventing visual glitches.
useRef gives you DOM access, useLayoutEffect gives you the right timing to measure it.
Users only see your corrected layout, never the intermediate states.
Blocks painting and can hurt performance. Only use when absolutely necessary.