服务端组件
Server Component 在哪里执行?
- 执行环境: 在与客户端分离的服务端环境运行,可发生于构建期,也可发生于请求时;
- 数据访问: 可直接读取数据库或文件并使用 async/await;
- 渲染结果: 输出可与 Client Components 组合的 React 结果,再由框架组织传输、HTML 渲染与导航;
async function Article({ id }) {
const article = await database.articles.find(id);
return (
<article>
<h1>{article.title}</h1>
<p>{article.body}</p>
</article>
);
}
为什么 Server Components 不等于 SSR?
- 职责差异: Server Components 决定组件代码在哪里运行与哪些代码发送到客户端,SSR 则把 React 输出转成初始 HTML;
- 可组合: 同一应用可以使用 Server Components 并对包含 Client Components 的页面做 SSR,客户端组件并非永远不经过服务器预渲染;
- 交互边界: 需要 state、事件、Effect 或浏览器能力的部分由 Client Component 承担;
如何组合服务端内容与客户端交互?
- 服务端父级: 可以渲染客户端组件,将准备好的可序列化数据传入;
- 内容插槽: Server Component 可把服务端生成的 JSX 作为 children 交给客户端容器;
- 导入边界: 客户端模块不能直接导入依赖数据库等服务端专用能力的组件;边界按模块依赖判断,而不是只看最终渲染嵌套;
async function Page() {
return (
<InteractivePanel>
<Article id="intro" />
</InteractivePanel>
);
}
"use client";
import { useState } from "react";
export function InteractivePanel({ children }) {
const [expanded, setExpanded] = useState(false);
return (
<section>
<button onClick={() => setExpanded((value) => !value)}>展开内容</button>
{expanded && children}
</section>
);
}
哪些能力不能直接放进 Server Component?
- 客户端状态: 不调用 useState、useEffect 等客户端生命周期能力,也不能直接接收普通浏览器事件回调作为可传输结果;
- 浏览器对象: window、document 与 DOM ref 不属于该执行环境,放到明确客户端边界;
- 指令区别: Server Components 不靠 'use server' 声明,后者标记服务端可调用函数,指令细节见边界指令;
采用服务端组件需要什么基础设施?
- 框架支持: 需要兼容的打包器、路由和传输协议集成,普通 createRoot 项目不会自动获得完整 RSC 管线;
- 版本边界: 面向应用的能力与框架底层集成接口具有不同稳定性,框架作者应锁定兼容版本,不把内部接口当作普通应用 API;