Appearance
第1章:React Server 技术概览
1.1 什么是服务端渲染 (SSR)
定义与核心概念
服务端渲染(Server-Side Rendering,SSR)是指在服务器上执行 React 组件的渲染过程,生成完整的 HTML 字符串,然后发送给客户端的技术。与传统的客户端渲染(CSR)不同,SSR 在用户首次访问时就能看到完整的页面内容。
SSR vs CSR 对比
特性 | 服务端渲染 (SSR) | 客户端渲染 (CSR) |
---|---|---|
首屏加载 | 快速显示内容 | 需要等待 JS 加载执行 |
SEO 友好 | 搜索引擎可直接抓取 | 需要额外配置 |
服务器负载 | 较高 | 较低 |
交互性 | 需要 Hydration | 立即可交互 |
缓存策略 | 复杂 | 简单 |
SSR 工作流程图
基础 SSR 示例
javascript
// server.js - 基础 SSR 服务器
import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './App.js';
const server = express();
server.get('/', (req, res) => {
// 1. 获取数据
const data = { user: 'John', posts: ['Post 1', 'Post 2'] };
// 2. 渲染 React 组件为 HTML 字符串
const html = renderToString(<App data={data} />);
// 3. 生成完整的 HTML 页面
const fullHtml = `
<!DOCTYPE html>
<html>
<head>
<title>SSR App</title>
</head>
<body>
<div id="root">${html}</div>
<script>
window.__INITIAL_DATA__ = ${JSON.stringify(data)};
</script>
<script src="/bundle.js"></script>
</body>
</html>
`;
res.send(fullHtml);
});
server.listen(3000);
javascript
// App.js - React 组件
import React from 'react';
function App({ data }) {
return (
<div>
<h1>欢迎, {data.user}!</h1>
<ul>
{data.posts.map((post, index) => (
<li key={index}>{post}</li>
))}
</ul>
</div>
);
}
export default App;
javascript
// client.js - 客户端 Hydration
import React from 'react';
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
// 获取服务器传递的初始数据
const data = window.__INITIAL_DATA__;
// Hydration:将服务器渲染的 HTML 转换为可交互的 React 应用
hydrateRoot(
document.getElementById('root'),
<App data={data} />
);
1.2 传统 SSR vs React Server Components
传统 SSR 的局限性
双重渲染问题
- 服务器渲染一次
- 客户端 Hydration 再渲染一次
- 造成性能浪费和复杂性
Bundle 大小问题
- 所有组件代码都需要发送到客户端
- 即使某些组件只在服务器使用
数据获取复杂性
- 需要在服务器和客户端都处理数据获取逻辑
- 容易出现数据不一致问题
React Server Components 的优势
RSC vs 传统 SSR 对比示例
传统 SSR 方式:
javascript
// 传统 SSR - 所有组件都需要在客户端运行
function BlogPost({ id }) {
const [post, setPost] = useState(null);
const [comments, setComments] = useState([]);
useEffect(() => {
// 客户端需要重新获取数据
fetchPost(id).then(setPost);
fetchComments(id).then(setComments);
}, [id]);
if (!post) return <div>Loading...</div>;
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
<CommentList comments={comments} />
<CommentForm postId={id} />
</article>
);
}
React Server Components 方式:
javascript
// Server Component - 只在服务器运行
async function BlogPost({ id }) {
// 直接在服务器获取数据,不需要客户端重新获取
const post = await db.posts.findById(id);
const comments = await db.comments.findByPostId(id);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
<CommentList comments={comments} />
{/* 只有交互组件需要在客户端运行 */}
<CommentForm postId={id} />
</article>
);
}
// Client Component - 在客户端运行
'use client';
function CommentForm({ postId }) {
const [comment, setComment] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
await submitComment(postId, comment);
setComment('');
};
return (
<form onSubmit={handleSubmit}>
<textarea
value={comment}
onChange={(e) => setComment(e.target.value)}
/>
<button type="submit">提交评论</button>
</form>
);
}
1.3 React Server 生态系统架构
整体架构图
技术栈层次图
1.4 核心包介绍与职责划分
react-dom/server
职责: 传统 SSR 的核心实现
主要 API:
javascript
// 基础渲染 API
import {
renderToString, // 同步渲染为字符串
renderToStaticMarkup, // 渲染为静态 HTML(无 React 属性)
renderToPipeableStream, // Node.js 流式渲染
renderToReadableStream // Web Streams 渲染
} from 'react-dom/server';
// 使用示例
const html = renderToString(<App />);
// 流式渲染示例
const stream = renderToPipeableStream(<App />, {
onShellReady() {
response.statusCode = 200;
response.setHeader('Content-type', 'text/html');
stream.pipe(response);
},
onError(error) {
console.error('SSR Error:', error);
}
});
源码结构:
react-dom/src/server/
├── ReactDOMServer.js # 主入口文件
├── ReactDOMServerLegacy.js # 传统 API 实现
├── ReactDOMFizzServer.js # Fizz 渲染器(流式)
├── ReactDOMFizzStatic.js # 静态渲染
└── ReactDOMServerBrowser.js # 浏览器环境适配
react-server
职责: React Server Components 的核心实现
主要功能:
- Server Components 的渲染逻辑
- React Flight 协议的实现
- 组件序列化和反序列化
javascript
// Server Component 示例
// 注意:这是在服务器环境中运行的
async function ServerComponent({ userId }) {
// 直接访问数据库或 API
const user = await database.users.findById(userId);
const posts = await database.posts.findByUserId(userId);
return (
<div>
<UserProfile user={user} />
<PostList posts={posts} />
{/* 客户端组件 */}
<InteractiveWidget userId={userId} />
</div>
);
}
react-server-dom-webpack
职责: Webpack 打包工具的 RSC 集成
主要功能:
- 客户端/服务端代码分离
- 模块引用解析
- 代码分割优化
javascript
// webpack.config.js 配置示例
const ReactServerWebpackPlugin = require('react-server-dom-webpack/plugin');
module.exports = {
plugins: [
new ReactServerWebpackPlugin({
isServer: false, // 客户端构建
clientReferences: './src/client-references.js'
})
],
resolve: {
conditionNames: ['react-server', 'import', 'require']
}
};
react-server-dom-turbopack
职责: Turbopack 打包工具的 RSC 集成
特点:
- 更快的构建速度
- 更好的开发体验
- 实验性功能支持
包之间的依赖关系图
数据流向图
传统 SSR 数据流
React Server Components 数据流
性能对比分析
Bundle 大小对比
首屏加载时间对比
实际应用场景
1. 电商网站产品页面
javascript
// Server Component - 产品详情页
async function ProductPage({ productId }) {
// 服务器直接查询数据库
const product = await db.products.findById(productId);
const reviews = await db.reviews.findByProductId(productId);
const recommendations = await db.products.getRecommendations(productId);
return (
<div>
{/* 静态内容,不需要客户端 JS */}
<ProductInfo product={product} />
<ReviewList reviews={reviews} />
{/* 交互组件,需要客户端 JS */}
<AddToCartButton productId={productId} />
<ProductRecommendations products={recommendations} />
</div>
);
}
// Client Component - 购物车按钮
'use client';
function AddToCartButton({ productId }) {
const [isAdding, setIsAdding] = useState(false);
const handleAddToCart = async () => {
setIsAdding(true);
await addToCart(productId);
setIsAdding(false);
};
return (
<button
onClick={handleAddToCart}
disabled={isAdding}
>
{isAdding ? '添加中...' : '加入购物车'}
</button>
);
}
2. 博客文章页面
javascript
// Server Component - 文章页面
async function ArticlePage({ slug }) {
const article = await cms.articles.findBySlug(slug);
const author = await cms.authors.findById(article.authorId);
const relatedArticles = await cms.articles.getRelated(article.tags);
return (
<article>
<header>
<h1>{article.title}</h1>
<AuthorInfo author={author} />
<PublishDate date={article.publishedAt} />
</header>
<main>
<ArticleContent content={article.content} />
</main>
<aside>
<RelatedArticles articles={relatedArticles} />
{/* 交互组件 */}
<ShareButtons url={article.url} title={article.title} />
<CommentSection articleId={article.id} />
</aside>
</article>
);
}
小结
本章介绍了 React Server 技术的基础概念,包括:
- SSR 基础:理解服务端渲染的工作原理和优势
- 技术对比:传统 SSR 与 React Server Components 的区别
- 生态架构:React Server 相关包的职责和关系
- 实际应用:真实场景中的使用示例
下一章我们将深入探讨 React Server 技术的演进历程,了解从 React 15 到 React 19 的发展脉络。
