React 16: Warning: Expected server HTML to contain a matching <div> in <body>
ReactjsReactjs Problem Overview
Since upgrading to React 16 I get this error message:
warning.js:33 Warning: Expected server HTML to contain a matching <div> in <body>.
What is generally causing this error message and how can it be fixed?
Reactjs Solutions
Solution 1 - Reactjs
If you use ReactDOM.hydrate
to start web application, you will see this warning.
If your application does not use server-side rendering (ssr
), please use ReactDOM.render
to start.
Solution 2 - Reactjs
If you're using Server Side Rendering like NextJS, delete recent code and compare if you've tried to access a variable directly inside of Component scope where DOM is not guaranteed yet. For me, it was:
import { i18n } from 'i18n'
export default function SomeComponent() {
const initLanguage = i18n.language <---- causing error
return ...
}
If you need to access such properties, access it within useEffect
, so as to make sure that document
is already established by then. It is kinda equivalent to componentDidMount()
:
import { i18n } from 'i18n'
import { useEffect, useState } from 'react'
export default function SomeComponent() {
const [initlanguage, setInitLanguage] = useState('en')
useEffect(() => setInitLanguage(i18n.language), [])
return ...
}
Solution 3 - Reactjs
If your HTML code is like
<table>
<tr>
you can get this error.
To get around it, use the <tbody> tag like
<table>
<tbody>
<tr>
Don't forget to close the tag(s)!
Solution 4 - Reactjs
This seems to be because of Browsersync inserting a script tag in the body on client side that does not exist on server side. Thus React fails to attach to the server render.
Solution 5 - Reactjs
I got this using material UI by trying to do const searchParams = new URLSearchParams(process.browser ? window.location.search : '')
at the top of the react component in my NextJS app with material-ui SnackBar, I was able to remove the error by putting this in a useEffect
hook.
Entire component for reference:
export default function SnackBarMessage() {
const [requestLogin, setRequestLogin] = useState(false)
const handleClose = (event, reason) => {
if (reason === 'clickaway') {
return
}
setRequestLogin(false)
}
useEffect(() => {
// had to move into a useEffect hook
const searchParams = new URLSearchParams(process.browser ? window.location.search : '')
const hasRequestLogin = Boolean(searchParams.get('requestLogin'))
if (hasRequestLogin) {
setRequestLogin(true)
}
}, [])
return (
<>
{requestLogin && (
<Snackbar open={requestLogin} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity='error' style={{ fontSize: '18px' }} elevation={6}>
Please Log Back In
</Alert>
</Snackbar>
)}
</>
)
}
Solution 6 - Reactjs
In my case it was because of using PersistGate
and react-loadable
.
if you using this libraries, you could use preloadAll instead of preloadReady
Solution 7 - Reactjs
In my case i installed REACTFUL and it do a render so different by default install:
src/renderers/dom.js
ReactDOM.hydrate(
<App initialData={window.__R_DATA.initialData} />,
document.getElementById('root'),
);
src/renderers/server.js
const initialData = {
appName: 'Reactful',
};
return Promise.resolve({
initialData,
initialMarkup: ReactDOMServer.renderToString(
<App initialData={initialData} />,
),
pageData,
});
care with initialData!
i fix it changed dom.js like it, attention to initialData is important:
const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate;
const initialData = {
appName: 'Reactful',
};
renderMethod(
<App initialData={initialData} />,
document.getElementById('root'),
);
Solution 8 - Reactjs
The issue can be caused because the client and server mismatch during HMR updates
I resolved that way:
const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydrate
const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydrate
renderMethod(
<AppContainer>
<Comp />
</AppContainer>,
document.getElementById('root')
)
Solution 9 - Reactjs
Looks like you're trying to access a prop in a dom before is ready. You can use a structure like this:
{(variable) && sameVariable}
Solution 10 - Reactjs
I'm assuming you are using ssr. The warning is about attempting to render before there is a window object. You need to hydrate.
ReactDOM.hydrate(<App />, document.getElementById("home"))
What I don't understand, is that the App component is being served static by express. Why is it trying to render before it is served? Bring on the comments.