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

Next.js 13(App目录)className不匹配警告及样式加载异常求助

修复Next.js 13 App目录中styled-components + MUI的className不匹配与样式闪烁问题

问题根源

你同时使用了styled-components和MUI基于Emotion的styled两个独立样式系统,但当前仅配置了styled-components的服务端样式注入,缺少MUI(Emotion)的服务端样式处理,导致:

  1. 服务端未渲染MUI自定义样式,客户端hydration时补全样式出现闪烁
  2. 服务端与客户端生成的className不一致,触发「Prop className did not match」警告

具体修复步骤

1. 添加MUI Emotion的服务端样式注册表

创建EmotionRegistry.tsx组件,处理MUI样式的服务端注入:

"use client";
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";

export default function EmotionRegistry({ children }: { children: React.ReactNode }) {
  const [cache] = useState(() => {
    const cache = createCache({ key: "mui-style" });
    cache.compat = true;
    return cache;
  });

  useServerInsertedHTML(() => {
    return (
      <style
        data-emotion={`${cache.key} ${Object.keys(cache.inserted).join(" ")}`}
        dangerouslySetInnerHTML={{
          __html: Object.values(cache.inserted).join(" "),
        }}
      />
    );
  });

  return <CacheProvider value={cache}>{children}</CacheProvider>;
}

2. 修复StyledComponentsRegistry的客户端逻辑

当前组件在客户端直接返回children,导致客户端与服务端className生成逻辑不一致,修改为:

"use client";
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";

export default function StyledComponentsRegistry({
  children,
}: { children: React.ReactNode; }) {
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());

  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    return <>{styles}</>;
  });

  // 客户端也用StyleSheetManager包裹,保证className生成规则一致
  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      {children}
    </StyleSheetManager>
  );
}

3. 调整根Layout的组件嵌套顺序

将两个样式注册表按正确顺序嵌套,确保MUI的主题和样式能正常生效:

"use client";
import Navbar from "../components/navbar/Navbar";
import { ThemeProvider } from "@mui/material";
import theme from "../theme";
import "../globals.css";
import { Inter } from "next/font/google";
import StyledComponentsRegistry from "../components/StyledComponentsRegistry";
import EmotionRegistry from "../components/EmotionRegistry"; // 导入新组件

const inter = Inter({ subsets: ["latin"] });

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        {/* 先包裹Emotion处理MUI样式,再包裹styled-components */}
        <EmotionRegistry>
          <StyledComponentsRegistry>
            <ThemeProvider theme={theme}>{children}</ThemeProvider>
          </StyledComponentsRegistry>
        </EmotionRegistry>
      </body>
    </html>
  );
}

4. 可选:统一样式系统(推荐)

如果不需要同时维护两个样式系统,建议统一用styled-components创建MUI自定义样式,避免冲突:

// styles.ts 改用styled-components的styled
import styled from "styled-components";

export const PromoStyled = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  .tagline {
    max-width: 600px;
    font-size: 40px;
    font-weight: 900;
    opacity: 90%;
    color: ${(props) => props.theme.palette.primary.main};
    text-shadow: #e0ffce -1px 0px, #e0ffce 0px 3px, #e0ffce 3px 0px,
      #e0ffce 0px -1px, #e0ffce 5px 7px 0px;
  }

  .teaser-image {
    margin-top: 20px;
  }
`;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 21:00:24