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

升级至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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:24:26