我试图让SSR在我的应用程序中工作,但出现错误:
Hydration 失败,因为初始 UI 与服务器上呈现的内容不匹配。
现场演示代码在这里。
问题的现场演示在这里(打开开发工具控制台查看错误):
import React from "react";
class App extends React.Component {
head() {
return (
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<title>React App</title>
</head>
);
}
body() {
return (
<body>
<div className="App">
<h1>Client says Hello World</h1>
</div>
</body>
);
}
render() {
return (
<React.Fragment>
{this.head()}
{this.body()}
</React.Fragment>
)
}
}
export default App;
Run Code Online (Sandbox Code Playgroud)
import React from "react";
import * as ReactDOM from "react-dom/client";
import { StrictMode } from "react";
import App from "./App";
//const container = document.getElementById("root");
const container = document.getElementsByTagName("html")[0]
ReactDOM.hydrateRoot(
container,
<StrictMode>
<App />
</StrictMode>
);
Run Code Online (Sandbox Code Playgroud)
现场演示中显示的 HTML 模板由后端提供服务并使用以下代码生成:
const ReactDOMServer = require('react-dom/server');
const clientHtml = ReactDOMServer.renderToString(
<StrictMode>
<App />
</StrictMode>
)
// Serve clientHtml to client
Run Code Online (Sandbox Code Playgroud)
我需要动态生成<head></head> and <body></body>
App 类中所示的部分。
小智 368
我最近在 Next.js 中遇到了同样的问题,我不确定我的观察结果是否适用于其他库。
我一直用不正确的标签包装我的组件,也就是说,Next.js 不喜欢用p标签包装你的div、sections等,所以它会大喊“水合失败,因为初始 UI 与渲染的内容不匹配”在服务器上”。
我通过检查元素如何相互包裹来解决这个问题。对于Material UI,您需要谨慎。例如,如果您使用排版组件作为包装器,则组件属性的默认值为“p”,因此如果您不将组件值更改为某种语义,您将遇到错误。
在我看来,根据我个人的经验,该问题是由 HTML 元素排列不当引起的,要在 Next.js 的上下文中解决该问题,必须重新评估他们如何排列 HTML 元素。
import Image from 'next/image'
/**
* This might give that error
*/
export const IncorrectComponent = ()=>{
return(
<p>
<div>This is not correct and should never be done because the p tag has been abused</div>
<Image src='/vercel.svg' alt='' width='30' height='30'/>
</p>
)
}
/**
* This will work
*/
export const CorrectComponent = ()=>{
return(
<div>
<div>This is correct and should work because a div is really good for this task.</div>
<Image src='/vercel.svg' alt='' width='30' height='30'/>
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
小智 73
导入和运行某些包也可能导致此错误。例如,当我使用 Swiper.js 包时,我遇到了这个问题。这主要是因为包在某处使用 Window 对象。
由于修改包本身的内容并不是一个好的做法,因此解决此类问题的最佳方法是仅在加载 DOM 后渲染组件。所以你可以试试这个。
const Index = () => {
const [domLoaded, setDomLoaded] = useState(false);
useEffect(() => {
setDomLoaded(true);
}, []);
return (
<>
{domLoaded && (
<Swiper>
<div>Test</div>
</Swiper>
)}
</>
);
};
export default Index;
Run Code Online (Sandbox Code Playgroud)
dgk*_*nca 35
如果您使用的是table
,您可能错过了<tbody>
。
错误:
<table>
<tr>
<td>a</td>
<td>b</td>
</tr>
</table>
Run Code Online (Sandbox Code Playgroud)
正确的:
<table>
<tbody>
<tr>
<td>a</td>
<td>b</td>
</tr>
</tbody>
</table>
Run Code Online (Sandbox Code Playgroud)
San*_*Ali 21
那么让我解释一下为什么您的 Next.js 应用程序中会出现此错误。
有些标签不能在另一个标签内使用。例如,您不能在标签div
内使用td
。您不能p
在span
. table
其他标签如、ul
等也是如此。
更新:https: //html.spec.whatwg.org/上的文章可以帮助理解为什么会出现此错误。
您需要转到代码并删除所有使用的无效标签。就我而言,我使用了一个无效的a
标签。span
这是无效的
<span>
<a target="_blank" href="https://askhumans.io"> Login </a>
</span>
Run Code Online (Sandbox Code Playgroud)
这是有效的。
<a target="_blank" href="https://askhumans.io"> <span> Login </span> </a>
Run Code Online (Sandbox Code Playgroud)
Min*_*ang 17
这使得应用程序在客户端呈现。这个对我有用:
export default function MyApp({ Component, pageProps }: AppProps) {
const [showChild, setShowChild] = useState(false);
useEffect(() => {
setShowChild(true);
}, []);
if (!showChild) {
return null;
}
if (typeof window === 'undefined') {
return <></>;
} else {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
}
Run Code Online (Sandbox Code Playgroud)
han*_*ast 11
该错误具有误导性,因为它与水合作用无关,而是与错误嵌套的标签有关。我通过删除 HTML 内容并重新加载页面来找出冲突的标签,直到找到问题(二分搜索)。
就我而言,这是由<a>
内部引起的<Link>
。我认为Next.js 需要<a>
链接内的 ,但显然情况并非如此/不再是这样。
请参阅有关tag的 Next.js 文档<Link>
。
小智 5
我有 React 18.2.0 和 Next.js 12.2.4,我用以下代码修复了水合作用:
import { useEffect, useState } from 'react'
import { Breakpoint, BreakpointProvider } from 'react-socks';
import '../styles/globals.scss'
function MyApp({ Component, pageProps }) {
const [showChild, setShowChild] = useState(false)
useEffect(() => {
setShowChild(true)
}, [])
if (!showChild) {
return null
}
return (
<BreakpointProvider>
<Component {...pageProps} />
</BreakpointProvider>
)
}
export default MyApp
Run Code Online (Sandbox Code Playgroud)
小智 5
只需进入浏览器,Chrome \xe2\x86\x92 右上角三栏按钮(汉堡菜单) \xe2\x86\x92 更多工具 \xe2\x86\x92 清除浏览历史记录 \xe2\x86\x92 删除 cookies。
\n不再有错误。
\n 归档时间: |
|
查看次数: |
405498 次 |
最近记录: |