useEffect and useLayoutEffect share the same signature and cleanup rules, but they run at different moments. useEffect runs after the browser paints, while useLayoutEffect runs after the DOM updates but before the paint. Choose useEffect by default and reach for useLayoutEffect only when the UI would visibly flicker otherwise.
The same Hook, a different moment
Both Hooks take a setup function and a dependency array. The difference is when React calls the setup after a commit.
| useEffect | useLayoutEffect | |
|---|---|---|
| Runs | After the browser paints | After DOM commit, before paint |
| Blocks painting | No | Yes |
| Typical use | Data, timers, subscriptions | Layout measurements |
Because useLayoutEffect blocks the paint, every state update inside it delays what the user sees. That is why the React docs recommend preferring useEffect whenever possible. The cleanup rules are identical, and both Hooks run one extra setup and cleanup cycle in development under Strict Mode.
When the paint timing matters
A tooltip needs its own height to decide whether it fits above or below the target. If you measure with useEffect, the first paint shows the wrong position and then it jumps.
import { useLayoutEffect, useRef, useState } from "react";
function Tooltip() {
const ref = useRef(null);
const [height, setHeight] = useState(0);
useLayoutEffect(() => {
setHeight(ref.current.getBoundingClientRect().height);
}, []);
return (
<div ref={ref} className="tooltip">
Hover text
</div>
);
}The component renders once with an unknown height, then measures the DOM and re-renders, all before the browser paints. The user sees only the final, correctly positioned tooltip. With useEffect, the same measurement happens after the browser has already shown the tooltip in its initial spot, so fast users see a flicker.
When useEffect is the right default
Data fetching, timers, subscriptions, and analytics never need to block the paint. Anything that does not read layout information should stay in useEffect so the browser can paint first. useEffect lets the browser show the frame first, then the Effect runs.
useEffect(() => {
const id = setInterval(() => setTicks((t) => t + 1), 1000);
return () => clearInterval(id);
}, []);There is no measurement here, so useLayoutEffect would only make the first frame slower with no visible benefit.
The server rendering caveat
useLayoutEffect has no layout information on the server, so React logs a warning during server rendering. The warning appears because there is no layout to measure before the HTML is generated. If a component needs it, keep that component client-only or render it only after hydration.
What to learn next
React useEffect explained covers the shared API, and how to synchronize React with browser APIs shows the subscription pattern both Hooks rely on. For reading DOM sizes safely, the refs section covers measuring elements on demand.
Rune AI
Key Insights
- useEffect runs after the browser paints; useLayoutEffect runs before.
- useLayoutEffect blocks painting, so it can make the page slower.
- Use useLayoutEffect for layout measurements that would otherwise flicker.
- useLayoutEffect does nothing on the server, so keep it in client-only components.
Frequently Asked Questions
When should I use useLayoutEffect?
Why not use useLayoutEffect everywhere?
Does useLayoutEffect run on the server?
Conclusion
useEffect and useLayoutEffect share a signature but run at different moments. Default to useEffect, and switch to useLayoutEffect only when a measurement must happen before the next paint.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.