升级至Next 13/React 18后Emotion出现FOUC问题求助
问题解答
是的,React 18 和 Next.js 13 的 SSR 机制变化确实会导致 Emotion 11.x 出现 FOUC(无样式内容闪烁)问题,核心原因在于流式渲染的引入以及 React 18 对 SSR API 的更新,未修改的旧版 Emotion 配置无法适配新的渲染逻辑。
具体变化点
- React 18 替换了传统的
renderToString,默认使用renderToPipeableStream实现流式 SSR,页面内容会分块发送到浏览器,而旧版 Emotion 的样式收集逻辑是同步绑定在完整渲染流程中的,无法跟上流式渲染的分块节奏,导致样式注入滞后于内容渲染。 - Next.js 13 的 App Router 默认启用流式渲染,即使是 Pages Router,升级后也会默认使用 React 18 的新 SSR API,直接打破了之前 Emotion 与 Next.js SSR 的兼容逻辑。
修复方案
1. 确保 Emotion 版本兼容
升级 @emotion/react、@emotion/styled 和 @emotion/server 到 11.10.0 及以上版本,该版本开始适配 React 18 的流式渲染 API。
2. Pages Router 适配配置
修改 _document.js,使用 Emotion 针对 React 18 优化的 SSR 收集逻辑:
import Document, { Html, Head, Main, NextScript } from 'next/document' import { cache } from '@emotion/react' import createEmotionServer from '@emotion/server/create-instance' const { extractCriticalToChunks, constructStyleTagsFromChunks } = createEmotionServer(cache) export default class MyDocument extends Document { static async getInitialProps(ctx) { const initialProps = await Document.getInitialProps(ctx) // 适配 React 18 流式渲染的样式收集 const chunks = extractCriticalToChunks(initialProps.html) const styles = constructStyleTagsFromChunks(chunks) return { ...initialProps, styles: [...initialProps.styles, styles], } } render() { return ( <Html> <Head> <meta name="emotion-insertion-point" content="" /> </Head> <body> <Main /> <NextScript /> </body> </Html> ) } }
3. App Router 适配配置
在 App Router 的根布局(app/layout.js)中添加 CacheProvider,确保服务器组件和客户端组件的样式同步:
'use client' import { CacheProvider } from '@emotion/react' import createCache from '@emotion/cache' const cache = createCache({ key: 'css', prepend: true }) export default function RootLayout({ children }) { return ( <html lang="en"> <body> <CacheProvider value={cache}>{children}</CacheProvider> </body> </html> ) }
注意:
use client指令是必须的,因为 Emotion 的CacheProvider属于客户端组件。
4. 临时禁用流式渲染(应急方案)
如果暂时无法调整配置,可以在 next.config.js 中禁用流式渲染:
/** @type {import('next').NextConfig} */ const nextConfig = { experimental: { streaming: false, }, } module.exports = nextConfig
内容的提问来源于stack exchange,提问作者mikematos84
相关产品推荐
相关产品推荐

