
react server components 运行在服务端,不执行浏览器环境代码,因此无法访问 `document` 或任何 dom api;其渲染产物是序列化的虚拟 dom 指令,而非 html 字符串,故 css 变量等运行时 dom 操作必须交由 client component 完成。
React Server Components(RSC)本质上是纯函数式、无副作用的服务端计算单元。它们在 Node.js 环境中执行,不挂载到真实 DOM,也不具备浏览器全局对象(如 window、document、localStorage)。RSC 的核心职责是:安全地获取数据、组合 UI 结构、生成轻量级的序列化指令(如 ["$","div",null,{"className":"card"}]),再由客户端 React Runtime 解析并渲染为真实 DOM。
这意味着以下操作在 RSC 中严格禁止且会直接报错:
// ❌ 错误:RSC 中 document 未定义
"use server";
export default function ServerComponent() {
// 运行时抛出 ReferenceError: document is not defined
document.documentElement.style.setProperty("--theme-color", "#3b82f6");
return Hello;
}为什么不能操作 CSS 变量?
CSS 自定义属性(--foo)是浏览器渲染引擎在样式计算阶段读取的运行时状态,依赖于已挂载的 document 对象。而 RSC 输出的是 JSON-like 序列化结构,并不生成或修改 HTML 字符串——它甚至不“知道”最终 HTML 长什么样。真正的 HTML 构建发生在客户端(或 SSR/SSG 阶段,与 RSC 分离)。
正确的协作模式:RSC + RCC
推荐架构是职责分离:
- ✅ RSC 负责数据获取与逻辑处理(如 fetch 用户偏好、主题配置);
- ✅ 通过 props 将数据传递给 Client Component;
- ✅ RCC 在 useEffect 中安全操作 DOM:
// app/page.tsx (RSC)
import ClientThemeApplier from "./ClientThemeApplier";
export default async function Page() {
const theme = await fetchTheme(); // 服务端获取
return ;
}
// app/ClientThemeApplier.tsx (RCC)
"use client";
import { useEffect } from "react";
export default function ClientThemeApplier({ theme }: { theme: { primary: string } }) {
useEffect(() => {
document.documentElement.style.setProperty(
"--primary-color",
theme.primary
);
}, [theme.primary]);
return Content;
}替代方案:服务端预计算样式(非 DOM 操作)
若目标是“服务端决定样式并内联生效”,可考虑:
- Tailwind CSS + 动态 class:RSC 根据数据返回预设 class 名(如 "bg-blue-500"),客户端直接渲染;
- CSS-in-JS 库(如 Emotion)服务端注入:配合 Next.js App Router 的 generateStaticParams 或自定义 SSR 流程,在 HTML 中注入
- 静态生成(SSG)时写入 CSS 变量:构建时生成含 :root { --color: #xxx; } 的 CSS 文件。
⚠️ 注意:这些都不是“RSC 操作 DOM”,而是利用构建/渲染流程在服务端影响最终输出的 CSS 或 HTML 结构。
总结
- RSC ≠ SSR:RSC 不生成 HTML,只生成 React 序列化指令;
- DOM 操作(含 CSS 变量)必须在客户端完成,使用 "use client" 标记的组件;
- 最佳实践是 RSC 做数据层,RCC 做表现层,通过 props 明确通信;
- 若需首屏样式即生效,优先通过服务端生成的 CSS 或内联 style 属性实现,而非尝试绕过 React 渲染模型。
理解这一边界,是构建高性能、可维护 React 服务端应用的关键前提。










