This warning appears during server-side rendering when React encounters useLayoutEffect in a component. Since there is no DOM on the server, layout effects cannot run, which will cause a mismatch between server and client rendering.
This warning occurs when you use useLayoutEffect in a component that is being rendered on the server (SSR/SSG). The useLayoutEffect hook is designed to run synchronously after all DOM mutations but before the browser paints, allowing you to measure layout and synchronously re-render. However, during server-side rendering, there is no actual DOM to measure or manipulate. React emits this warning specifically for useLayoutEffect (not useEffect) because useLayoutEffect is typically used to perform DOM measurements or manipulations before the user sees the rendered component. When the server-rendered HTML reaches the browser, React will hydrate it and run the useLayoutEffect for the first time, potentially causing a visual jump or mismatch if the effect changes what the user sees. The warning indicates that your component's initial server-rendered output may not match what the client renders after hydration, leading to potential layout shifts, visual inconsistencies, or hydration errors.
If your effect doesn't need to run before the browser paints (e.g., logging, data fetching, subscriptions), replace useLayoutEffect with useEffect:
// Before
import { useLayoutEffect } from 'react';
function MyComponent() {
useLayoutEffect(() => {
console.log('Component mounted');
}, []);
}
// After
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log('Component mounted');
}, []);
}useEffect runs asynchronously after the paint, preventing the server warning and avoiding blocking the initial render.
Create a custom hook that uses useEffect on the server and useLayoutEffect on the client:
// lib/hooks/useIsomorphicLayoutEffect.ts
import { useEffect, useLayoutEffect } from 'react';
const useIsomorphicLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
export default useIsomorphicLayoutEffect;Then use it in your components:
import useIsomorphicLayoutEffect from '@/lib/hooks/useIsomorphicLayoutEffect';
function MyComponent() {
useIsomorphicLayoutEffect(() => {
// This runs as useLayoutEffect on client, useEffect on server
const element = document.getElementById('my-element');
const height = element?.offsetHeight;
// ...
}, []);
}This pattern is used by major libraries like react-redux and react-beautiful-dnd.
For components that absolutely need layout effects, render them only after the client has hydrated:
import { useEffect, useState, useLayoutEffect } from 'react';
function MyComponent() {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
useLayoutEffect(() => {
if (!isClient) return;
// Safe to use layout effect now
const rect = element.getBoundingClientRect();
// ...
}, [isClient]);
if (!isClient) {
return <div>Loading...</div>; // Fallback for SSR
}
return <div>{/* Actual content */}</div>;
}This ensures the server renders a fallback while the client renders the full component with layout effects.
In Next.js, use dynamic imports with ssr: false to prevent server-side rendering:
// app/page.tsx
import dynamic from 'next/dynamic';
const ClientOnlyComponent = dynamic(
() => import('@/components/ClientOnlyComponent'),
{ ssr: false }
);
export default function Page() {
return (
<div>
<h1>My Page</h1>
<ClientOnlyComponent />
</div>
);
}In the component:
// components/ClientOnlyComponent.tsx
import { useLayoutEffect, useState } from 'react';
export default function ClientOnlyComponent() {
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useLayoutEffect(() => {
// No warning - this only runs on client
setDimensions({
width: window.innerWidth,
height: window.innerHeight
});
}, []);
return <div>Window: {dimensions.width}x{dimensions.height}</div>;
}If the warning comes from a library you cannot modify, you can suppress it using React's DevTools or by patching the library. However, first check if the library has an SSR-compatible version or configuration.
For Next.js, you can suppress specific warnings in next.config.js:
// next.config.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
// Suppress client-side warnings
config.resolve.fallback = {
...config.resolve.fallback,
};
}
return config;
},
};Or update the library if a newer version fixes SSR compatibility (common with react-redux 7.1+, framer-motion, etc.).
Wrap components using layout effects in Suspense boundaries to defer their rendering until client hydration:
import { Suspense } from 'react';
function Page() {
return (
<div>
<h1>Content above suspense renders immediately</h1>
<Suspense fallback={<div>Loading interactive content...</div>}>
<ComponentWithLayoutEffect />
</Suspense>
</div>
);
}This allows the server to render a fallback while the component with layout effects only renders on the client after hydration.
Why React warns only for useLayoutEffect: While both useEffect and useLayoutEffect cannot affect server-rendered output, React specifically warns about useLayoutEffect because it typically modifies the DOM before paint. Using it during SSR creates an unavoidable mismatch - the server has no DOM to measure, but the client will measure and potentially re-render before the user sees anything, causing layout shifts.
Performance considerations: useLayoutEffect blocks the browser from painting until the effect completes. On the server, this doesn't matter (no browser), but on the client, it can delay time-to-first-paint. Only use useLayoutEffect when you must prevent visual flashing (e.g., tooltip positioning, DOM measurements for animations). For most cases, useEffect is sufficient.
React 18 and Suspense: In React 18, Suspense handles client-only rendering more gracefully. You can mark components as client-only by placing them inside Suspense boundaries, and React will skip server rendering them automatically.
Popular library patterns: Libraries like react-redux (v7.1+), framer-motion (v6+), and react-beautiful-dnd have adopted useIsomorphicLayoutEffect internally to prevent this warning. If you see warnings from these libraries, update to the latest version first.
Next.js specific: Next.js 13+ with app router uses Server Components by default, which never run client hooks. Add "use client" at the top of files using useLayoutEffect, and Next.js will handle client-only rendering automatically.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite