React 16:警告:由于状态<div>,预计服务器 HTML 将在 <div> 中包含匹配的

问题描述 投票:0回答:8

我使用 SSR 时遇到以下错误

Warning: Expected server HTML to contain a matching <div> in <div>.

问题出在客户端,检查组件安装时的浏览器宽度,然后设置组件的状态以呈现其移动版本。

但是服务器默认容器的桌面版本,因为它不知道浏览器宽度。

遇到这样的情况我该如何处理?我可以以某种方式检测服务器上的浏览器宽度并在发送到客户端之前渲染移动容器吗?

编辑:现在我决定在组件安装时渲染容器。这样,服务器端和客户端最初都不会渲染任何内容来阻止此错误。

我仍然愿意接受更好的解决方案

reactjs isomorphic-javascript client-hints
8个回答
36
投票

这将解决问题。

// Fix: Expected server HTML to contain a matching <a> in
const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate;
renderMethod(
  <BrowserRouter>
    <RoutersController data={data} routes={routes} />
  </BrowserRouter>,
  document.getElementById('root')
);

22
投票

盖茨比

最近的 gatsby 功能标志(在 2020 年 12 月 v2.28 中引入)能够在开发环境中服务器端渲染页面。

此标志默认设置为

true
。在这种情况下,您可能会在控制台中看到此错误消息

Warning: Expected server HTML to contain a matching <div> in <div>.

您可以在

gatsby.config.js
文件中禁用此标志:

module.exports = {
  flags: {
    DEV_SSR: false,
  }
}

文档:https://www.gatsbyjs.com/docs/reference/release-notes/v2.28/#feature-flags-in-gatsby-configjs


10
投票

出现此消息的原因也可能是错误的代码,无法在 SSR 和 CSR 之间呈现一致的内容,因此

hydrate
无法解析。

例如SSR返回:

...
<div id="root">
   <div id="myDiv">My div content</div>
</div>
...

企业社会责任回归时:

...
<div id="root">
    <div id="anotherDiv">My other div content</div>
</div>
...

在这种情况下,最好的解决方案不是安装库或关闭

hydrate
,而是实际修复代码中的不一致之处。

暂时从

<script src="/react-bundle-path.js"></script>
中删除
index.js
有助于将 SSR 渲染的确切内容与 CSR
hydrate
渲染的内容进行比较。


9
投票

当前接受的答案与 TypeScript 配合得不好。这对我有用。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="shortcut icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
  </body>
</html>
import React from "react"
import { hydrate, render } from "react-dom"
import BrowserRouter from "./routers/Browser"

const root = document.getElementById("root")
var renderMethod
if (root && root.innerHTML !== "") {
  renderMethod = hydrate
} else {
  renderMethod = render
}
renderMethod(<BrowserRouter />, document.getElementById("root"))

3
投票

来自 https://github.com/vercel/next.js/discussions/17443#discussioncomment-87097

仅应在浏览器中运行的代码应在

useEffect
内执行。这是必需的,因为第一次渲染应该与服务器的初始渲染匹配。如果你操纵这个结果,它会产生不匹配,并且 React 将无法成功地水合页面。

当您在

window
内运行仅限浏览器的代码(例如尝试访问
useEffect
)时,它会在水合后发生 👍



1
投票

我的解决方案是使用像 express-useragent 这样的中间件来检测浏览器用户代理。

然后,在服务器端,按照以下规则创建一个类似

viewsize
{width, height}

if (ua.isMobile) {
  return {width: 360, height: 480}
}

if (ua.isDesktop) {
  return {width: 768, height: 600}
}

return {width: 360, height: 480} // default, and for bot

那么,某种程度上它仍然是SSR中的响应式设计。


0
投票

就我而言,我必须将“Provider of Redux”和“Toaster”放置在根布局的 body 标记内。

export default function RootLayout({ children }) {
      return (
        <>
          <html lang="en">
            <body className={inter.className}>
            <Toaster position="top-right" reverseOrder={false} toastOptions={{ duration: 1000 }} />
              <StoreProvider>
                {children}
              </StoreProvider>
            </body>
          </html>
        </>
      )
    }
© www.soinside.com 2019 - 2024. All rights reserved.