You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 15搭配Styled Components出现Hydration失败问题求助

NextJS v15 + Styled Components 水化失败问题求助

我在使用NextJS v15和Styled Components时一直碰到水化(Hydration)失败的错误,代码仓库地址:https://github.com/mr-greg/portfolio-v2。我已经尝试配置了如下的_document.js,也试过其他多种方案,但都没解决问题。希望找到不用停用Styled Components的解决办法,谢谢!

本地控制台错误信息如下:

Console Error

Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used

  • A server/client branch if (typeof window !== 'undefined').
  • Variable input such as Date.now() or Math.random() which changes each time it's called.
  • Date formatting in a user's locale which doesn't match the server.
  • External changing data without sending a snapshot of it along with the HTML.
  • Invalid HTML tag nesting.

It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.

See more info here: https://nextjs.org/docs/messages/react-hydration-error

  • className="sc-dntaoT kwpLBb"
  • className="sc-blHHSb mSnUo"
  • className="sc-ivxoEo iaVHeu"
  • className="sc-gtLWhw fYVTpf"
  • className="sc-gtLWhw jcqRrQ"
  • className="sc-egkSDF iVPGTD"
  • className="sc-egkSDF bnNXfG"
  • className="sc-fAUdSK dGZodg"
  • className="sc-fAUdSK cxJxcn"
  • className="sc-dntaoT uKlRd"
  • className="sc-fAUdSK cxJxcn"
  • className="sc-dntaoT uKlRd"
  • className="sc-fAUdSK cxJxcn"

我尝试的_document.js配置:

import Document from 'next/document';
import { ServerStyleSheet } from 'styled-components';

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

解决办法

从错误日志看,核心问题是服务端生成的Styled Components类名与客户端不匹配,导致HTML结构不一致触发水化失败。可按以下步骤排查修复:

1. 适配NextJS v15的路由模式

如果项目使用App Router,原_document.js仅对Pages Router生效,需在app/layout.js中重新配置Styled Components的服务端样式收集:

'use client';
import { createGlobalStyle } from 'styled-components';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  /* 你的全局样式内容 */
`;

export default function RootLayout({ children }) {
  useServerInsertedHTML(() => {
    const sheet = new ServerStyleSheet();
    const styles = sheet.getStyleElement();
    sheet.seal();
    return styles;
  });

  return (
    <html lang="en">
      <body>
        <GlobalStyle />
        {children}
      </body>
    </html>
  );
}

2. 清理依赖客户端环境的动态逻辑

  • 避免在服务端渲染组件中用typeof window !== 'undefined'直接切换样式,此类分支会导致两端渲染结果不一致。若必须依赖客户端环境,将组件标记为'use client',并把相关逻辑放到useEffect中执行(确保在水化完成后运行)。
  • 检查是否使用Math.random()、Date.now()这类每次取值不同的函数生成样式或类名,这类值会导致两端类名不匹配。如需随机值,在客户端组件的useEffect中生成并存入状态。

3. 校验HTML标签嵌套合法性

错误提示提及无效HTML嵌套(比如<a>嵌套<div>、<p>嵌套<div>等),会导致两端解析后的DOM结构不一致。检查所有Styled Components渲染的HTML标签,确保嵌套符合规范。

4. 排除浏览器扩展干扰

部分浏览器扩展会修改页面HTML,导致React水化时不匹配。可在隐私模式下打开页面测试,确认是否为扩展问题。

5. 升级Styled Components到兼容版本

确保styled-components版本与NextJS v15兼容,建议安装最新稳定版:

npm install styled-components@latest

6. 统一主题与全局样式

若使用ThemeProvider,确保服务端与客户端使用的主题完全一致,避免主题中包含依赖客户端窗口大小等动态值,防止两端渲染差异。

内容的提问来源于stack exchange,提问作者Zaack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:23:10