What does useLayoutEffect() do during SSR?
A reminder: what useLayoutEffect() does in client-side React
useLayoutEffect() is the "synchronous" counterpart of useEffect():
| Hook | When it fires |
|---|---|
useEffect() | already after the browser has painted the DOM (asynchronously) |
useLayoutEffect() | right after React updates the DOM, but before the screen paints |
That means
useLayoutEffect()lets you:
- measure element sizes,
- change the layout synchronously,
- or perform DOM mutations before the user sees the screen.
What happens during SSR
During Server-Side Rendering, React has no access to the DOM.
- No
window, - no
document, - no real elements.
So any DOM operations inside useLayoutEffect() are impossible.
That's why React doesn't call this hook at all on the server.
useLayoutEffect()'s behavior in SSR
On the server:
- React fully ignores every
useLayoutEffect()(anduseEffect()too). - The code inside it never runs at all.
- The component renders "cleanly" - it just returns JSX -> HTML.
On the client (after hydration):
- React runs
useLayoutEffect()once, once hydration finishes and the DOM is available. - If the hook contains side effects, they only fire after the HTML already exists in the browser.
A possible issue - a console warning
If you use useLayoutEffect() inside a component that renders both on the server and the client, React may print a warning:
Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format.or
Warning: useLayoutEffect is not supported during server rendering.This isn't an error, just a warning: React is simply telling you that your layout effect will be ignored during SSR.
How to avoid the problem
Option 1. Replace useLayoutEffect with useEffect, if possible
If your code doesn't depend on precise DOM measurements, it's better to just use useEffect:
useEffect(() => {
console.log('Safe for SSR');
}, []);Option 2. Wrap the call in an environment check
If you still need useLayoutEffect (e.g. for canvas, measurements, and animations),
you can safely define a "universal" hook:
import { useLayoutEffect, useEffect } from 'react';
// A safe hook for SSR
export const useIsomorphicLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect;Now you can write:
useIsomorphicLayoutEffect(() => {
const rect = ref.current.getBoundingClientRect();
console.log(rect);
}, []);On the server, useEffect runs (so nothing happens),
and in the browser, the real useLayoutEffect runs.
Option 3. Run DOM-dependent code only after hydration
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
setHydrated(true);
}, []);
if (!hydrated) return null;
useLayoutEffect(() => {
// This code only runs on the client, after hydration
}, []);Summary
| Environment | What useLayoutEffect() does |
|---|---|
| Server (SSR) | Fully ignored - not called, the DOM is unavailable |
| Client (after hydration) | Runs synchronously after the HTML is inserted into the DOM |
| If used in an SSR component | May trigger a warning, but not an error |
| Solution | Use useIsomorphicLayoutEffect or useEffect |
The key takeaway
useLayoutEffectdoesn't work on the server. React simply skips it during SSR, and only runs it after the HTML has already been rendered and "brought to life" on the client.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.