x icon indicating copy to clipboard operation
x copied to clipboard

在nextjs中使用时,页面初始化时组件会闪烁

Open xinnian999 opened this issue 7 months ago • 13 comments

重现步骤

在线示例链接:https://github.com/xinnian999/interview-mate

步骤: 1.clone我的代码 2.pnpm dev即可复现

当前行为

已经按照文档使用了AntdRegistry,但只对antd的组件生效了,对antd-x的组件没有效果

https://github.com/user-attachments/assets/3aa4dff8-d7c0-4192-bce2-5bd7eb07442d

预期行为

AntdRegistry可以对antd和antd-x的组件都生效

Image

上下文

No response

版本

1.4.0

您在哪些浏览器上遇到了这个问题?

Chrome

xinnian999 avatar Jul 11 '25 08:07 xinnian999

Hi @xinnian999! I'm Dosu and I’m helping the x team.

你遇到的闪烁(FOUC)问题,是因为 AntdRegistry 只会收集 antd 组件的样式,而不会自动收集 antd-x 组件的样式。antd-x 采用 cssinjs 方案,但目前没有像 AntdRegistry 这样的 SSR 样式收集器或注册器,所以 Next.js SSR 时 antd-x 组件的样式不会提前注入,导致页面初始化时样式闪烁。相关源码说明

cssinjs 提供了 useStyleRegister 和 extractStyle 等 SSR 支持方法,但 antd-x 组件库本身没有暴露类似 AntdRegistry 的顶层封装。要解决这个问题,需要在 Next.js 的 SSR 流程中手动调用 cssinjs 的样式收集方法,把 antd-x 组件的样式也注入到 HTML 里,否则就会出现你描述的闪烁现象。相关机制说明

目前 SSG(静态生成)无法解决这个问题,只有 SSR 能彻底避免首次渲染时的样式闪烁,这是 cssinjs 目前的技术限制。

总结:

  • AntdRegistry 只对 antd 生效,对 antd-x 无效。
  • antd-x 没有类似 AntdRegistry 的 SSR 样式收集器。
  • 需要手动用 cssinjs 的 extractStyle 等方法收集 antd-x 样式并注入 SSR HTML。
  • SSG 无法解决,必须用 SSR。

如需具体 Next.js 集成方案或代码示例,可以进一步说明需求。

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

dosubot[bot] avatar Jul 11 '25 08:07 dosubot[bot]

Hi @xinnian999! I'm Dosu and I’m helping the x team.

你遇到的闪烁(FOUC)问题,是因为 AntdRegistry 只会收集 antd 组件的样式,而不会自动收集 antd-x 组件的样式。antd-x 采用 cssinjs 方案,但目前没有像 AntdRegistry 这样的 SSR 样式收集器或注册器,所以 Next.js SSR 时 antd-x 组件的样式不会提前注入,导致页面初始化时样式闪烁。相关源码说明

cssinjs 提供了 useStyleRegister 和 extractStyle 等 SSR 支持方法,但 antd-x 组件库本身没有暴露类似 AntdRegistry 的顶层封装。要解决这个问题,需要在 Next.js 的 SSR 流程中手动调用 cssinjs 的样式收集方法,把 antd-x 组件的样式也注入到 HTML 里,否则就会出现你描述的闪烁现象。相关机制说明

目前 SSG(静态生成)无法解决这个问题,只有 SSR 能彻底避免首次渲染时的样式闪烁,这是 cssinjs 目前的技术限制。

总结:

  • AntdRegistry 只对 antd 生效,对 antd-x 无效。
  • antd-x 没有类似 AntdRegistry 的 SSR 样式收集器。
  • 需要手动用 cssinjs 的 extractStyle 等方法收集 antd-x 样式并注入 SSR HTML。
  • SSG 无法解决,必须用 SSR。

如需具体 Next.js 集成方案或代码示例,可以进一步说明需求。

To reply, just mention @dosu.

How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

手动用 cssinjs 的 extractStyle 等方法收集 antd-x 样式并注入 SSR HTML。这个可以给个示例吗

xinnian999 avatar Jul 11 '25 08:07 xinnian999

@dosu

afc163 avatar Jul 11 '25 15:07 afc163

你可以用 cssinjs 的 StyleProvider 和 extractStyle 手动收集 antd-x 的样式并注入到 SSR HTML,避免页面闪烁。核心思路是:每次 SSR 时创建一个独立的 style cache,包裹你的 App,然后在服务端渲染后用 extractStyle 拿到 CSS 字符串,插入到 HTML 的

下面是 Next.js(App Router)集成 antd-x SSR 样式收集的简化示例:

  1. 安装依赖(如果还没装):
pnpm add @ant-design/cssinjs
  1. app/layout.tsx(或自定义 _app.tsx)中:
// app/layout.tsx
import { StyleProvider, createCache, extractStyle } from '@ant-design/cssinjs';
import { XProvider } from '@ant-design/x';
import React from 'react';

export default function RootLayout({ children }) {
  // SSR 时每次请求都要新建 cache
  const styleCache = React.useMemo(() => createCache(), []);

  return (
    <html>
      <head>
        {/* 这里 SSR 时插入样式 */}
        {typeof window === 'undefined' && (
          <style
            // 这里假设你在 getInitialProps 或自定义 document 里调用 extractStyle
            dangerouslySetInnerHTML={{
              __html: extractStyle(styleCache),
            }}
          />
        )}
      </head>
      <body>
        <StyleProvider cache={styleCache}>
          <XProvider>
            {children}
          </XProvider>
        </StyleProvider>
      </body>
    </html>
  );
}
  1. 如果用自定义 _document.tsx(推荐),在 SSR 阶段插入样式:
// pages/_document.tsx
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { extractStyle, createCache } from '@ant-design/cssinjs';

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const styleCache = createCache();
    const originalRenderPage = ctx.renderPage;

    ctx.renderPage = () =>
      originalRenderPage({
        enhanceApp: (App) => (props) =>
          (
            <StyleProvider cache={styleCache}>
              <App {...props} />
            </StyleProvider>
          ),
      });

    const initialProps = await Document.getInitialProps(ctx);
    const css = extractStyle(styleCache);

    return {
      ...initialProps,
      styles: (
        <>
          {initialProps.styles}
          <style dangerouslySetInnerHTML={{ __html: css }} />
        </>
      ),
    };
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

注意事项:

  • antd-x 没有像 antd 那样的 AntdRegistry,必须用 cssinjs 的原生 API 手动收集和注入样式。
  • 如果 antd 和 antd-x 混用,建议分别处理各自的样式收集,确保都包裹在对应的 Provider 下,避免样式丢失或顺序错乱。
  • 每次 SSR 渲染都要新建 cache,不能复用,否则会有样式污染。

参考:cssinjs SSR 样式收集原理
antd-x 相关实现:GlobalLayout.tsx 用法示例

如需更详细的 Next.js 代码集成示例可以继续问!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

dosubot[bot] avatar Jul 11 '25 15:07 dosubot[bot]

你可以用 cssinjs 的 StyleProvider 和 extractStyle 手动收集 antd-x 的样式并注入到 SSR HTML,避免页面闪烁。核心思路是:每次 SSR 时创建一个独立的 style cache,包裹你的 App,然后在服务端渲染后用 extractStyle 拿到 CSS 字符串,插入到 HTML 的 。

下面是 Next.js(App Router)集成 antd-x SSR 样式收集的简化示例:

  1. 安装依赖(如果还没装):

pnpm add @ant-design/cssinjs 2. 在 app/layout.tsx(或自定义 _app.tsx)中:

// app/layout.tsx import { StyleProvider, createCache, extractStyle } from '@ant-design/cssinjs'; import { XProvider } from '@ant-design/x'; import React from 'react';

export default function RootLayout({ children }) { // SSR 时每次请求都要新建 cache const styleCache = React.useMemo(() => createCache(), []);

return (

{/* 这里 SSR 时插入样式 */} {typeof window === 'undefined' && ( <style // 这里假设你在 getInitialProps 或自定义 document 里调用 extractStyle dangerouslySetInnerHTML={{ __html: extractStyle(styleCache), }} /> )} <StyleProvider cache={styleCache}> <XProvider> {children} </XProvider> </StyleProvider> ); } 3. 如果用自定义 _document.tsx(推荐),在 SSR 阶段插入样式:

// pages/_document.tsx import Document, { Html, Head, Main, NextScript } from 'next/document'; import { extractStyle, createCache } from '@ant-design/cssinjs';

export default class MyDocument extends Document { static async getInitialProps(ctx) { const styleCache = createCache(); const originalRenderPage = ctx.renderPage;

ctx.renderPage = () =>
  originalRenderPage({
    enhanceApp: (App) => (props) =>
      (
        <StyleProvider cache={styleCache}>
          <App {...props} />
        </StyleProvider>
      ),
  });

const initialProps = await Document.getInitialProps(ctx);
const css = extractStyle(styleCache);

return {
  ...initialProps,
  styles: (
    <>
      {initialProps.styles}
      <style dangerouslySetInnerHTML={{ __html: css }} />
    </>
  ),
};

}

render() { return ( <Html> <Head />

<Main /> <NextScript /> </Html> ); } } 注意事项:
  • antd-x 没有像 antd 那样的 AntdRegistry,必须用 cssinjs 的原生 API 手动收集和注入样式。
  • 如果 antd 和 antd-x 混用,建议分别处理各自的样式收集,确保都包裹在对应的 Provider 下,避免样式丢失或顺序错乱。
  • 每次 SSR 渲染都要新建 cache,不能复用,否则会有样式污染。

参考:cssinjs SSR 样式收集原理 antd-x 相关实现:GlobalLayout.tsx 用法示例

如需更详细的 Next.js 代码集成示例可以继续问!

To reply, just mention @dosu.

How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

这个方案不可行,你所示例的组件是next的根组件,它是一个Server组件,不能调用useMemo和@ant-design/cssinjs里的api,会报错

xinnian999 avatar Jul 14 '25 02:07 xinnian999

这个库只有机器人回复吗

xinnian999 avatar Jul 14 '25 03:07 xinnian999

    "@ant-design/x": "^1.4.0",
+   "antd": "5.x",

@ant-design/x 依赖的应该是 antd 5.x,需要保持 antd 实例只有一个。

afc163 avatar Jul 14 '25 03:07 afc163

换成5.26.4了,但是没什么效果

xinnian999 avatar Jul 14 '25 03:07 xinnian999

@zombieJ 我测试了下,AntdRegistry生成的html中 style标签content内容是空,是正常的吗?不太了解这里的逻辑,但是感觉这里应该是从AntdRegistry以及底层cssinjs的extractStyle应该是要提取出样式来,提前ssr输出到head中,才对吧?

<style id="antd-cssinjs" data-rc-order="prepend" data-rc-priority="-1000">.data-ant-cssinjs-cache-path{content:"";}</style>

hylin avatar Jul 16 '25 11:07 hylin

@xinnian999 目前排查下来应该是底层cssinjs的问题,近期会进行修复

hylin avatar Jul 17 '25 11:07 hylin

在 @ant-design/[email protected] 尝试修复了下 Suspense 造成的 antd ssr 样式丢失问题,可以试下。

MadCcc avatar Jul 21 '25 10:07 MadCcc

在 @ant-design/[email protected] 尝试修复了下 Suspense 造成的 antd ssr 样式丢失问题,可以试下。

我在我这个项目里升级了v1.1.0版本,但还是没什么效果。。。

xinnian999 avatar Jul 21 '25 13:07 xinnian999

Image 我这边貌似没有复现闪烁呢

MadCcc avatar Jul 21 '25 14:07 MadCcc