【问题标题】:React 16: Warning: Expected server HTML to contain a matching <div> in <body>React 16:警告:期望服务器 HTML 在 <body> 中包含匹配的 <div>
【发布时间】:2018-03-08 16:37:13
【问题描述】:

自从升级到 React 16 后,我收到以下错误消息:

warning.js:33 Warning: Expected server HTML to contain a matching &lt;div&gt; in &lt;body&gt;.

通常是什么原因导致此错误消息以及如何解决?

【问题讨论】:

  • 你能显示一些代码吗?
  • 如果您在升级后看到意外情况,请提出问题并提供示例。否则我们无法知道有什么东西坏了。谢谢!
  • @DanAbramov 你是对的。事实证明这是一个与 React 无关的问题,但从 v16 开始,当需要 React 组件的地方注入客户端脚本标记(Browsersync)时,它无法水合,从而产生上述错误。在 React v15 中似乎并非如此。通过将插入的脚本标签移动到正文的末尾来修复。
  • @AntonHolmquist 你能解释更多细节吗?你把什么脚本移到了正文的末尾。我现在正面临这个警告。
  • 还有什么解决方案吗???

标签: reactjs


【解决方案1】:

如果您使用ReactDOM.hydrate 启动Web 应用程序,您将看到此警告。

如果您的应用程序不使用服务器端渲染 (ssr),请使用 ReactDOM.render 启动。

【讨论】:

  • suppressHydrationWarning={true} 属性也可以用于渲染元素。但是,作为文档点,这个道具必须很少使用。更好的解决方案是适当地使用hydrate()render()reactjs.org/docs/react-dom.html#hydrate
  • 那么,这个警告是为了什么?
【解决方案2】:

如果您正在使用像 NextJS 这样的服务器端渲染,请删除最近的代码并比较您是否尝试直接在 DOM 尚不能保证的组件范围内访问变量。对我来说是:

import { i18n } from 'i18n'

export default function SomeComponent() {
    const initLanguage = i18n.language              <---- causing error

    return ...
}

如果您需要访问这些属性,请在useEffect 内访问,以确保此时document 已经建立。有点相当于componentDidMount():

import { i18n } from 'i18n'
import { useEffect, useState } from 'react'

export default function SomeComponent() {
    const [initlanguage, setInitLanguage] = useState('en')

    useEffect(() => setInitLanguage(i18n.language), [])

    return ...
}

【讨论】:

  • 嗨@Lucia,如果我想从 useSelector() 获取数据会发生什么?我不能在 useEffect 中调用钩子。我也遇到了这个问题,它破坏了 Next.JS 中的 css。谢谢。
  • @rony 看看this answer
【解决方案3】:

如果你的 HTML 代码是这样的

<table>
  <tr>

你会得到这个错误。
要绕过它,请使用

标签,如
<table>
  <tbody>
    <tr>

别忘了关闭标签!

【讨论】:

  • next.js 中就是这样
  • 我正在处理遗留代码,在一个长的三元条件下,“else”输出是“没有找到结果......”但它在父 @ 内的 &lt;div&gt; 内987654324@。通过将&lt;div&gt; 更改为&lt;li&gt; 来修复它。
【解决方案4】:

这似乎是因为 Browsersync 在客户端的正文中插入了一个脚本标记,而该标记在服务器端不存在。因此 React 无法附加到服务器渲染。

【讨论】:

  • 那么解决办法是什么?
  • 我不使用身体作为 React 的容器,但在补水时也出现此错误。你是怎么解决的?
【解决方案5】:

我通过使用 Material UI 尝试在 NextJS 应用程序的 react 组件顶部使用 material-ui SnackBar 执行 const searchParams = new URLSearchParams(process.browser ? window.location.search : '') 来获得此错误,我可以通过将其放入 useEffect 挂钩来消除错误。

整个组件供参考:

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>
      )}
    </>
  )
}

【讨论】:

【解决方案6】:

就我而言,这是因为使用了PersistGatereact-loadable。 如果你使用这个库,你可以使用 preloadAll 而不是 preloadReady

【讨论】:

    【解决方案7】:

    在我的情况下,我安装了 REACTFUL,它在默认情况下进行了如此不同的渲染:

    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,
     });
    

    注意初始数据!

    我把它改了 dom.js 喜欢它,注意 initialData 很重要:

    const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate;
    const initialData = {
      appName: 'Reactful',
    };
    renderMethod(
      <App initialData={initialData} />,
      document.getElementById('root'),
    );
    

    【讨论】:

      【解决方案8】:

      此问题可能是由于 HMR 更新期间客户端和服务器不匹配造成的

      我是这样解决的:

      const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydra

      const renderMethod = !!module.hot ? ReactDOM.render : ReactDOM.hydrate
      renderMethod(
        <AppContainer>
          <Comp />
        </AppContainer>,
        document.getElementById('root')
      )
      

      【讨论】:

        【解决方案9】:

        看起来您正试图在准备好之前访问 dom 中的道具。您可以使用这样的结构:

        {(variable) && sameVariable}
        

        【讨论】:

          【解决方案10】:

          我假设您使用的是 ssr。警告是关于在有窗口对象之前尝试渲染。你需要补水。

          ReactDOM.hydrate(<App />, document.getElementById("home"))
          

          我不明白的是,App 组件是由 express 静态提供的。为什么它在服务之前尝试渲染?带上cmets。

          【讨论】:

            猜你喜欢
            • 2020-07-04
            • 1970-01-01
            • 2021-01-15
            • 2018-01-03
            • 2021-08-11
            • 2021-09-05
            • 1970-01-01
            • 2021-08-16
            • 2020-11-07
            相关资源
            最近更新 更多