extractStyle(cache) 必须在服务端渲染完成后立即调用,因为它依赖已注册的样式规则,需在 renderToString() 后、拼接 HTML 前执行,且客户端必须复用同一 cache 实例,配合 {plain: true, once: true} 输出纯 CSS。

为什么 extractStyle(cache) 必须在服务端渲染完成后立即调用
因为 extractStyle(cache) 读取的是当前 cache 中已注册的所有样式规则字符串,而这些规则只在组件渲染过程中被写入。如果在 renderToString() 或 renderToPipeableStream() 之前调用,cache 还是空的;如果在水合(hydration)之后才提取,客户端 JS 已开始运行,部分样式可能已被动态覆盖或丢弃。
常见错误是把它放在中间件或全局初始化里——此时根本没触发任何组件渲染,extractStyle(cache) 返回空字符串,
- 必须确保它在完整渲染完 React 树后、拼接 HTML 前执行
- 若用 Next.js App Router,要配合
useServerInsertedHTML的返回时机,不能提前 return - 若手动 SSR(如 Express + ReactDOMServer),应在
renderToString(rootElement)之后、res.send(html)之前调用
客户端 StyleProvider 复用 cache 的陷阱
客户端不是“新建一个 cache 再喂一遍组件”,而是必须复用服务端生成的那个 cache 实例,否则水合时无法识别已注入的样式,会重新计算并插入重复
典型失效现象:Button 没颜色、Input 边框变细、暗色模式下主题变量未生效——不是配置错了,而是客户端用了新 createCache(),跟服务端 cache 不兼容。
立即学习“前端免费学习笔记(深入)”;
- Next.js 中必须把 cache 作为
StyleProvider的 prop 传入,不能在组件内 useState(() => createCache()) - Ant Design 官方推荐用
@ant-design/nextjs-registry封装,但它要求项目中所有依赖的@ant-design/cssinjs版本完全一致 - 运行
npm ls @ant-design/cssinjs查版本,多个版本需用resolutions强制统一
extractStyle(cache, { once: true }) 和 plain: true 的区别
once: true 表示只提取当前 cache 中已注册的样式,不监听后续插入(适合 SSR 场景);plain: true 表示输出纯 CSS 字符串,不含 <script> 包裹逻辑——这是关键,否则你会得到一段 JS 代码试图动态插入 style,而不是可直接塞进 <style> 标签的内容。</script>
错误写法:extractStyle(cache) 默认返回带 document.head.appendChild(...) 的 JS 字符串,直接塞进 HTML 会报错或无效。
- 正确组合是:
extractStyle(cache, { plain: true, once: true }) - 输出结果应为纯 CSS 文本,需手动包裹
<style data-rc-order="prepend" id="antd-cssinjs">...</style> - 加
data-rc-order="prepend"是为了让 antd 的 runtime 样式不会覆盖它
SSR 注入后仍闪烁的隐藏原因
即使 cache 正确、extractStyle 调用时机对、客户端也复用了 cache,还是闪,大概率是动效组件(比如 Tooltip、Drawer、带 enter/exit 动画的 Alert)在首次渲染时触发了延迟样式注入——它们的动画 keyframes 或过渡类可能在初始 render 阶段未被收集到 cache 中。
这类组件往往依赖 useEffect 或 useState 触发二次样式注册,而 SSR 环境下 useEffect 不执行,导致服务端漏提。
- 解决方案:对含动画的组件,在服务端显式预渲染一次(哪怕不可见),强制触发样式注册
- 或降级使用
once: false+ 客户端补提(但会增加首屏 JS 执行负担) - 更稳妥的做法是禁用 SSR 阶段的动画(用
motion={false}或animate={false}属性)
真正难的不是“怎么注入”,而是判断哪些样式属于“服务端必须一次性提全”的边界——这个边界由组件内部是否含副作用决定,而非你写的 JSX 结构。


















