在nextjs中使用时,页面初始化时组件会闪烁
重现步骤
在线示例链接: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的组件都生效
上下文
No response
版本
1.4.0
您在哪些浏览器上遇到了这个问题?
Chrome
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
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
![]()
手动用 cssinjs 的 extractStyle 等方法收集 antd-x 样式并注入 SSR HTML。这个可以给个示例吗
@dosu
你可以用 cssinjs 的 StyleProvider 和 extractStyle 手动收集 antd-x 的样式并注入到 SSR HTML,避免页面闪烁。核心思路是:每次 SSR 时创建一个独立的 style cache,包裹你的 App,然后在服务端渲染后用 extractStyle 拿到 CSS 字符串,插入到 HTML 的
。下面是 Next.js(App Router)集成 antd-x SSR 样式收集的简化示例:
- 安装依赖(如果还没装):
pnpm add @ant-design/cssinjs
- 在
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>
);
}
- 如果用自定义
_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
你可以用 cssinjs 的 StyleProvider 和 extractStyle 手动收集 antd-x 的样式并注入到 SSR HTML,避免页面闪烁。核心思路是:每次 SSR 时创建一个独立的 style cache,包裹你的 App,然后在服务端渲染后用 extractStyle 拿到 CSS 字符串,插入到 HTML 的 。
下面是 Next.js(App Router)集成 antd-x SSR 样式收集的简化示例:
- 安装依赖(如果还没装):
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
![]()
这个方案不可行,你所示例的组件是next的根组件,它是一个Server组件,不能调用useMemo和@ant-design/cssinjs里的api,会报错
这个库只有机器人回复吗
"@ant-design/x": "^1.4.0",
+ "antd": "5.x",
@ant-design/x 依赖的应该是 antd 5.x,需要保持 antd 实例只有一个。
换成5.26.4了,但是没什么效果
@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>
@xinnian999 目前排查下来应该是底层cssinjs的问题,近期会进行修复
在 @ant-design/[email protected] 尝试修复了下 Suspense 造成的 antd ssr 样式丢失问题,可以试下。
在 @ant-design/[email protected] 尝试修复了下 Suspense 造成的 antd ssr 样式丢失问题,可以试下。
我在我这个项目里升级了v1.1.0版本,但还是没什么效果。。。