Next.js 13中使用MUI与Styled Components的FOUC问题求助
Next.js 13分为Pages Router和App Router两种路由模式,针对不同模式,Styled Components的FOUC问题有不同的适配方案,结合你使用MUI+Styled Components的场景,具体解决方案如下:
一、Pages Router 适配方案
你找到的Next.js 12的_document代码可以修改后适配Next.js 13的Pages Router,同时兼容Styled Components v6和MUI:
1. 安装编译优化依赖
先安装babel-plugin-styled-components,确保服务端渲染时样式正确注入:
npm install --save-dev babel-plugin-styled-components
2. 更新自定义_document.tsx/jsx
修改服务端样式收集逻辑,同时兼容MUI的服务端样式:
import Document, { Html, Head, Main, NextScript } from 'next/document'; import { ServerStyleSheet } from 'styled-components'; import { ServerStyleSheets as MuiServerStyleSheets } from '@mui/material/styles'; export default class MyDocument extends Document { static async getInitialProps(ctx) { const styledSheet = new ServerStyleSheet(); const muiSheets = new MuiServerStyleSheets(); const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => styledSheet.collectStyles(muiSheets.collect(<App {...props} />)), }); const initialProps = await Document.getInitialProps(ctx); return { ...initialProps, styles: [ initialProps.styles, muiSheets.getStyleElement(), styledSheet.getStyleElement(), ], }; } finally { styledSheet.seal(); } } render() { return ( <Html lang="en"> <Head /> <body> <Main /> <NextScript /> </body> </Html> ); } }
3. 配置Babel(可选但推荐)
在项目根目录创建.babelrc文件,优化Styled Components编译:
{ "presets": ["next/babel"], "plugins": [ [ "styled-components", { "ssr": true, "displayName": true, "preprocess": false } ] ] }
4. 确认MUI引擎配置
由于你已安装@mui/styled-engine-sc,MUI会自动使用Styled Components作为样式引擎。若样式优先级有问题,可在_app.tsx/jsx中添加配置:
import { ThemeProvider, createTheme } from '@mui/material/styles'; import { StyledEngineProvider } from '@mui/material/styles'; const theme = createTheme(); export default function App({ Component, pageProps }) { return ( <StyledEngineProvider injectFirst> <ThemeProvider theme={theme}> <Component {...pageProps} /> </ThemeProvider> </StyledEngineProvider> ); }
injectFirst可确保MUI样式不会被Styled Components覆盖,可根据需求调整。
二、App Router 适配方案
若你使用的是Next.js 13的App Router(app/目录),需要借助官方适配器处理服务端样式注入:
1. 安装适配器依赖
npm install @styled-components/nextjs-adapter
2. 修改next.config.js
启用Next.js对Styled Components的编译支持:
/** @type {import('next').NextConfig} */ const nextConfig = { compiler: { styledComponents: true, }, }; module.exports = nextConfig;
3. 配置Root Layout(app/layout.tsx)
在根布局中添加Styled Components和MUI的Provider,注意标记为客户端组件:
'use client'; import { StyledComponentsProvider } from '@styled-components/nextjs-adapter'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import { StyledEngineProvider } from '@mui/material/styles'; import { ReactNode } from 'react'; const theme = createTheme(); export default function RootLayout({ children }: { children: ReactNode }) { return ( <html lang="en"> <body> <StyledEngineProvider injectFirst> <ThemeProvider theme={theme}> <StyledComponentsProvider> {children} </StyledComponentsProvider> </ThemeProvider> </StyledEngineProvider> </body> </html> ); }
4. 客户端组件标记
所有使用Styled Components的组件必须添加'use client'指令,因为Styled Components属于客户端库,无法在Server Components中使用:
'use client'; import styled from 'styled-components'; const StyledButton = styled.button` background: #2196f3; color: white; padding: 8px 16px; border-radius: 4px; border: none; `; export default function MyButton() { return <StyledButton>点击按钮</StyledButton>; }
通用最佳实践
- App Router模式下,确保所有Styled Components代码都在标记了
'use client'的组件中 - 避免在服务端渲染组件中动态生成样式,尽量静态定义
- 构建后清理浏览器缓存,确保最新样式文件加载
- 检查是否存在重复的样式注入逻辑,避免冲突
内容的提问来源于stack exchange,提问作者Yonatan Galili

