Skip to content

第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 的局限性

  1. 双重渲染问题

    • 服务器渲染一次
    • 客户端 Hydration 再渲染一次
    • 造成性能浪费和复杂性
  2. Bundle 大小问题

    • 所有组件代码都需要发送到客户端
    • 即使某些组件只在服务器使用
  3. 数据获取复杂性

    • 需要在服务器和客户端都处理数据获取逻辑
    • 容易出现数据不一致问题

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 技术的基础概念,包括:

  1. SSR 基础:理解服务端渲染的工作原理和优势
  2. 技术对比:传统 SSR 与 React Server Components 的区别
  3. 生态架构:React Server 相关包的职责和关系
  4. 实际应用:真实场景中的使用示例

下一章我们将深入探讨 React Server 技术的演进历程,了解从 React 15 到 React 19 的发展脉络。


微信公众号二维码