React 16: Warning: Expected server HTML to contain a matching <div> in <body>
Asked Answered
I

13

75

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?

Indecorum answered 27/9, 2017 at 9:0 Comment(7)
Could you show some code?Istanbul
If you see something unexpected after the upgrade please file issues and provide examples. Otherwise we have no way to know something is broken. Thanks!Martyry
@DanAbramov You are right. This turned out to be an issue unrelated to React, but since v16 it fails to hydrate when a client side script tag is injected (Browsersync) where a React component is expected, giving the error above. This did not seem to be the case in React v15. Fixed by moving the inserted script tag to the end of the body.Indecorum
@AntonHolmquist can you explain more detail? what script did you move to the end of body. I am facing this warning now.Beak
@AntonHolmquist Did you solved this ?Tourniquet
any solution for this yet???Anemoscope
For me (on NextJS) just deleting the build output directory .next and restarting the dev server made the problem disappear.Immeasurable
M
37

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.

Majestic answered 14/11, 2017 at 2:59 Comment(2)
The suppressHydrationWarning={true} prop can also be used on the rendered element. However, as documentation points, this prop must be used scarcely. The better solution is using hydrate() or render() appropriately: reactjs.org/docs/react-dom.html#hydrateGloam
So, what is this warning for?Royce
O
44

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)!

Omphale answered 5/2, 2019 at 13:17 Comment(3)
This was the case in next.jsTidewater
I am working on legacy code, and in a long ternary condition, the "else" output is a "There's no results found..." but it was inside a <div> inside the parent <ul>. Fixed it by changing the <div> to <li>.Forenoon
Solved for me, thanksDeflect
M
37

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.

Majestic answered 14/11, 2017 at 2:59 Comment(2)
The suppressHydrationWarning={true} prop can also be used on the rendered element. However, as documentation points, this prop must be used scarcely. The better solution is using hydrate() or render() appropriately: reactjs.org/docs/react-dom.html#hydrateGloam
So, what is this warning for?Royce
W
33

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 ...
}
Windup answered 21/11, 2019 at 21:56 Comment(2)
hi @Lucia, what happened if I want to get data from useSelector() ? I can't call hooks inside useEffect. I'm having this problem too which ruin the css in Next.JS. THank you.Chitin
@Chitin Look at this answerClanton
I
3

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.

Indecorum answered 27/9, 2017 at 9:9 Comment(2)
So what is the solution?Tramroad
I don't use a body as container for React, but got this error too on hydrating. How do you fix it?Linares
M
2

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>
      )}
    </>
  )
}
Matthew answered 31/8, 2020 at 14:25 Comment(1)
I also had this while in GatsbyJS. In my case I ended up using the location data from props instead. css-tricks.com/how-to-the-get-current-page-url-in-gatsby/…Montemayor
C
1

In my case I got an error when upgrading to Next.js 13, specifically when using Drawer from @mui/material. It seems switching to server side components is not easy.

return (
  <Drawer
    anchor="left"
    onClose={onClose}
    open={open}
    PaperProps={{
      sx: {
        backgroundColor: 'neutral.900',
        color: '#FFFFFF',
        width: 280
      }
    }}
    sx={{zIndex: (theme) => theme.zIndex.appBar + 100}}
    // 'persistent' or 'permanent' throws error 
    variant="temporary"
  >
    {content}
  </Drawer>
);

Chimaera answered 2/2, 2023 at 19:14 Comment(1)
Hi Adilet, this is not an answer but a comment/question. Make sure to use the "Answer" textbox for actual answers to the original question. I'm not downvoting you at this point, but others will for sure :) .Babbittry
W
1

If using Remix SSR hydration and you see an error like:

Warning: Expected server HTML to contain a matching <head> in <html>

there is a known issue where browser plugins can cause this issue (you can verify it's plugins by trying to load the page in Incognito mode).

See this Github issue: https://github.com/remix-run/indie-stack/issues/184

Apparently you can disable this warning/error by adding suppressHydrationWarning={true} to your <html> tag but this didn't work for me

This is also described in Remix's Gotchas: https://remix.run/docs/en/1.14.3/pages/gotchas#md-browser-extensions-injecting-code

This has been a frustrating and known issue for a long time and I have no idea why the Remix team has still not fixed this :(

Wheatear answered 23/3, 2023 at 8:8 Comment(0)
K
0

In my case it was because of using PersistGate and react-loadable. if you using this libraries, you could use preloadAll instead of preloadReady

Klockau answered 25/12, 2019 at 12:22 Comment(0)
E
0

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'),
);
Ette answered 2/7, 2020 at 23:2 Comment(0)
T
0

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')
)
Throne answered 6/10, 2021 at 14:17 Comment(0)
R
0

tldr;

The solution: Use incognito

For me

Apparently, my case is that the extensions I have caused this. So the way I solve it is just go to Incognito mode where most of my extensions are disabled there. Adding this answer because none seem to try to answer directly.

Roden answered 7/5 at 4:18 Comment(0)
K
-1

Looks like you're trying to access a prop in a dom before is ready. You can use a structure like this:

{(variable) && sameVariable}
Kendallkendell answered 19/5, 2021 at 18:43 Comment(0)
M
-2

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.

Mistaken answered 6/10, 2019 at 21:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.