useLayoutEffect is a version of useEffect that fires before the browser repaints the screen.
Parameters
() => (() => void) | void
required
The function with your Effect’s logic. Your effect function can optionally return a cleanup function.
- React will call your effect function after React has updated the DOM but before the browser paints the screen
- React will call your cleanup function before the component is removed
- If dependencies change, React will run cleanup, then run your effect with new values
Array<mixed> | void | null
The list of all reactive values referenced inside the effect code. Works the same as
useEffect dependencies.- If omitted, the effect runs after every render
- If
[](empty array), the effect runs only once (on mount) - If
[dep1, dep2], the effect runs when any dependency changes
Returns
useLayoutEffect returns undefined.
Usage
Measuring layout before the browser repaints
Most components don’t need to know their position and size on the screen. They only return JSX. Then the browser calculates their layout and repaints the screen. Sometimes, that’s not enough. Imagine a tooltip that appears next to an element on hover. If there’s enough space, the tooltip should appear above the element, but if there isn’t enough space, it should appear below. To render the tooltip in the right position, you need to measure its height (before the browser paints):Tooltiprenders with initialtooltipHeight = 0(so tooltip might be wrongly positioned)- React places it in the DOM and runs the code in
useLayoutEffect useLayoutEffectmeasures the height of the tooltip content- React runs another render with the actual height
- Browser paints the tooltip in the correct position (user never sees it move)
Rendering in two passes and blocking the browser hurts performance. Try to avoid this when you can.
useEffect vs useLayoutEffect
- useEffect
- useLayoutEffect
When to use useLayoutEffect
Measuring elements
Preventing visual flicker
Reading scroll position
Synchronizing with third-party DOM
Common Patterns
Auto-focus with scroll adjustment
Matching element heights
TypeScript
Troubleshooting
I’m getting a warning in server-side rendering
useLayoutEffect doesn’t run on the server. You’ll see this warning:
- Use useEffect
- Conditional hook
- Client-only render
My component flickers
If you see a flicker, you might needuseLayoutEffect instead of useEffect:
Performance is slow
useLayoutEffect blocks the browser from painting. If your effect is slow, the UI will freeze:
When should I use useLayoutEffect?
UseuseLayoutEffect when:
- ✅ Measuring DOM elements (getBoundingClientRect, offsetHeight, etc.)
- ✅ Synchronous DOM mutations that affect layout
- ✅ Preventing visual flicker
- ✅ Reading scroll position
useEffect when:
- ✅ Data fetching
- ✅ Setting up subscriptions
- ✅ Logging
- ✅ Any side effect that doesn’t affect layout
- ✅ Most cases!
Best Practices
Start with useEffect
Always start withuseEffect. Only switch to useLayoutEffect if you:
- See visual flicker
- Need to measure the DOM
- Need to make synchronous DOM updates