This warning appears during server-side rendering when useLayoutEffect is called, because layout effects cannot run on the server where there is no DOM. React falls back to useEffect behavior, which can cause hydration mismatches between server and client renders.
This warning occurs when you use React's useLayoutEffect hook in a component that is being server-side rendered (SSR). The useLayoutEffect hook is designed to run synchronously after all DOM mutations but before the browser paints the screen, allowing you to read layout information and re-render synchronously if needed. However, on the server there is no DOM, no layout information, and no browser paint cycle. The server is generating HTML strings, not manipulating actual DOM nodes. When React encounters useLayoutEffect during server rendering, it cannot execute it because the underlying browser APIs don't exist in the Node.js environment. React falls back to treating useLayoutEffect like useEffect during SSR, but warns you about this behavior because it can lead to hydration mismatches. The initial server-rendered HTML won't include the effects of your layout effect, but when the component hydrates on the client, useLayoutEffect will run and potentially change the UI, causing a flash of incorrect content or hydration warnings.
The most common solution is to create a hook that uses useLayoutEffect in the browser and useEffect on the server. This pattern is used by many popular libraries:
import { useEffect, useLayoutEffect } from 'react';
const useIsomorphicLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
export default useIsomorphicLayoutEffect;Then replace all useLayoutEffect calls with this custom hook:
import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';
function MyComponent() {
useIsomorphicLayoutEffect(() => {
// Your layout effect logic
}, []);
}This eliminates the warning while maintaining synchronous layout reading on the client.
If you don't actually need synchronous layout measurements before paint, simply use useEffect instead:
// Before
useLayoutEffect(() => {
// Some logic
}, [deps]);
// After
useEffect(() => {
// Same logic
}, [deps]);This is appropriate when:
- You're not reading layout information (offsetWidth, getBoundingClientRect, etc.)
- A brief flash of content is acceptable
- The effect doesn't need to block visual updates
React's official documentation suggests this approach when the timing difference doesn't matter.
For components that absolutely require layout effects, delay their rendering until the client-side hydration completes:
import { useEffect, useLayoutEffect, useState } from 'react';
function ComponentWithLayoutEffect() {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
useLayoutEffect(() => {
// Your layout effect logic
}, []);
if (!isMounted) {
return <div>Loading...</div>; // Fallback for SSR
}
return <div>Real content with layout effects</div>;
}This ensures the server and client render the same initial HTML (the loading state), then switches to the real content only on the client.
In Next.js, you can prevent server-side rendering of specific components using dynamic imports with ssr: false:
import dynamic from 'next/dynamic';
const ClientOnlyComponent = dynamic(
() => import('../components/ComponentWithLayoutEffect'),
{ ssr: false }
);
export default function Page() {
return <ClientOnlyComponent />;
}This tells Next.js to skip server rendering for that component entirely, replacing it with a loading fallback during SSR. The component will only render on the client where useLayoutEffect works normally.
If you're using useLayoutEffect to synchronize with external stores or data sources, React 18+ provides useSyncExternalStore which properly handles SSR:
import { useSyncExternalStore } from 'react';
function useMediaQuery(query: string) {
return useSyncExternalStore(
(callback) => {
const mediaQuery = window.matchMedia(query);
mediaQuery.addEventListener('change', callback);
return () => mediaQuery.removeEventListener('change', callback);
},
() => window.matchMedia(query).matches,
() => false // Server-side snapshot
);
}This hook supports server rendering and prevents hydration mismatches by accepting a separate snapshot for SSR.
If the warning comes from a third-party library you can't modify, suppress it temporarily while the library maintainers fix it:
// In your app entry point or component file
const originalError = console.error;
console.error = (...args) => {
if (
typeof args[0] === 'string' &&
args[0].includes('useLayoutEffect does nothing on the server')
) {
return;
}
originalError(...args);
};Warning: Only use this as a temporary workaround. It hides the symptom but doesn't fix potential hydration issues. Check if the library has an updated version or open an issue with the maintainers.
After implementing your fix, check that you haven't introduced hydration mismatches:
# Run your app and check browser console
npm run devLook for warnings like:
- "Text content does not match server-rendered HTML"
- "Hydration failed because the initial UI does not match"
- "There was an error while hydrating"
Also test with React DevTools profiler to ensure your fix doesn't cause unnecessary re-renders or layout thrashing.
Framework-Specific Considerations:
In Next.js App Router (React Server Components), this warning is less common because Client Components are clearly marked with "use client" directives. However, it can still occur when mixing server and client boundaries incorrectly.
In Remix, the warning often appears with third-party UI libraries. Remix's streaming SSR architecture makes the useIsomorphicLayoutEffect pattern even more important.
The Isomorphic Layout Effect Debate:
There's ongoing discussion in the React community about whether the useIsomorphicLayoutEffect pattern is a good practice. Some argue it's a necessary pragmatic solution, while others (including some React core team members) suggest it can hide real bugs. The article "There's no such thing as an isomorphic layout effect" by Sean Mores explains why this pattern might not be semantically correct for all use cases.
Performance Impact:
Switching from useLayoutEffect to useEffect changes when your code runs. useLayoutEffect blocks the browser paint, while useEffect runs after paint. If you're measuring and adjusting layout, using useEffect can cause a visible flash of incorrect layout. The useIsomorphicLayoutEffect pattern preserves the correct timing on the client while avoiding SSR warnings.
Libraries Known to Trigger This Warning:
Common libraries that may cause this warning include: react-dnd, framer-motion, react-hook-form, recharts, react-redux (older versions), and react-google-maps. Many have fixed or are working on fixes. Always check for library updates before implementing workarounds.
React.FC expects children prop to be defined
React.FC no longer includes implicit children prop
Warning: You provided a `selected` prop to a form field without an `onChange` handler
You provided a 'selected' prop without an onChange handler
Failed to load source map from suspense chunk
How to fix "Failed to load source map from suspense chunk" in React
Prop spreading could cause security issues
Prop spreading could cause security issues
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