Warning: Expected server HTML to contain a matching <div> in <div>. #17443
-
Hi, I have a navbar , and it displays a different UI based on if a user is logged in or not. I decided to keep track of if user is logged in by reading a cookie. Here is a relevant part of code:
My issue is that when I hard reload a page or load it for the first time I get this warning in my console and some part of CSS is broken :
After I navigate on a client to any other page this warning does not appear any more and CSS is fixed. I was able to pinpoint the issue, and if I comment out this part in my code the error is gone :
Of course, my navbar logic is broken in this case. I realize that there is no cookies on the server side, therefore to prevent it running on the server I check where the code is executed in this line What am I doing wrong? Why do I get this warning and have some broken CSS? Why is |
Beta Was this translation helpful? Give feedback.
Replies: 14 comments 28 replies
-
Code that is only supposed to run in the browser should be executed inside When you run browser only code (like trying to access |
Beta Was this translation helpful? Give feedback.
-
This snippet solved the problem. import {useState, useEffect} from 'react'
export default function Loading() {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true)
}, [])
return mounted && <div>Run on client only</div>
} Check the comments below if you have a problem with scroll restoration. |
Beta Was this translation helpful? Give feedback.
-
react doc about suppressHydrationWarning <div suppressHydrationWarning={true}>
{ process.browser && <MyAwesomeComponent /> }
<div>some other component</div>
</div>
thanks to https://blog.hao.dev/render-client-side-only-component-in-next-js |
Beta Was this translation helpful? Give feedback.
-
I think the solutions discussed here work fine when you have to hide / not render the component at all on the server, but what if you have to render a different variant of the component on server vs client (say, responsive design, where based on screen size we decide which variant of the component to render. We don't detect the device type on server and hence it always renders the desktop view, while on client, on mobile, it just rehydrates, finds a mismatch and then ends up recreating the whole DOM once again) |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Did it with @meotimdihia's solution, then replaced it with simple use of @@ -1,15 +1,13 @@
import type { NextPage } from "next";
import Head from "next/head";
-import { useState, useEffect } from "react";
-import { make as App } from "../src/components/app/App.bs";
+import dynamic from "next/dynamic";
-const Home: NextPage = () => {
- const [mounted, setMounted] = useState(false);
-
- useEffect(() => {
- setMounted(true);
- }, []);
+const App = dynamic<object>(
+ () => import("../src/components/app/App.bs").then((mod) => mod.make),
+ { ssr: false },
+);
+const Home: NextPage = () => {
return (
<>
<Head>
@@ -18,7 +16,7 @@ const Home: NextPage = () => {
<link rel="icon" href="/favicon.ico" />
</Head>
- {mounted && <App />}
+ <App />
</>
);
};``` |
Beta Was this translation helpful? Give feedback.
-
In my case the warning appeared when I had a protected page client side. ClientOnly.tsx
Protected.tsx
Usage
|
Beta Was this translation helpful? Give feedback.
-
thank you. brothers I also share my examples. Next.JS & TypsScript
Affter
|
Beta Was this translation helpful? Give feedback.
-
Hi I was able to solve an Error I was having with FontAwesome Icons and Next.js. I was getting the Error Error: Hydration failed because the initial UI does not match what was rendered on the server. And in console.log in the Browser it was showing Warning: Expected server HTML to contain a matching in .I applied a solution above to have a state called mounted, setMounted and trigger fontAwesome icon to render only when mounted is true Here is my component
|
Beta Was this translation helpful? Give feedback.
-
if you are using next js 13 and face this problem then you have to go for the styled-component. |
Beta Was this translation helpful? Give feedback.
-
Why function MyComponent() {
// useMemo will run in server-side & client-side
// Error: window is not defined in server
const color = useMemo(()=> {
return window.globalColor;
}, [])
return <h1 className={`title ${color}`}>Hello World!</h1>
} To fix this issue, you need to use useEffect to run the render only in the client-side. function MyComponent() {
const [color, setColor] = useState()
useEffect(() => {
setColor(window.globalColor)
}, [])
return <h1 className={`title ${color}`}>Hello World!</h1>
} Furthermore, wrap the solution above in a hook function useClientMemo<T>(fn: () => T, deps?: DependencyList): T {
const [data, setData] = React.useState<T>();
React.useEffect(() => {
setData(fn());
}, deps);
return data;
}
export default useClientMemo; Then, simply use: function MyComponent() {
const color = useClientMemo(()=> {
return window.globalColor;
}, [])
return <h1 className={`title ${color}`}>Hello World!</h1>
} Explanation:
|
Beta Was this translation helpful? Give feedback.
-
Also watch out about browser extensions that display elements in the page. I had an extension that used to display an icon in form inputs, and that was the problem as it was modifying the html. |
Beta Was this translation helpful? Give feedback.
-
Check you Layout component and put all in body |
Beta Was this translation helpful? Give feedback.
Code that is only supposed to run in the browser should be executed inside
useEffect
. That's required because the first render should match the initial render of the server. If you manipulate that result it creates a mismatch and React won't be able to hydrate the page successfully.When you run browser only code (like trying to access
window
) insideuseEffect
, it will happen after hydration 👍