展示 Next.js 服务端渲染 (SSR) 和 React Server Components (RSC) 特性
RSC 是 Next.js 13+ 的核心特性,允许组件在服务端渲染,同时保持与客户端组件的灵活混合。
⏳ 等待挂载...
使用 React Suspense,页面可以边加载边显示,不需要等待所有数据加载完成!
⏱️ 用户需要等待 1.5s+
⚡ 用户立即看到页面!
实现方式:使用 <Suspense> 包裹慢速组件, 提供 fallback 加载状态。Next.js 会自动处理流式传输。
📤 第一块 (Chunk 1)
HTML 头部、CSS、初始页面结构
📤 第二块 (Chunk 2)
快速组件的 HTML(立即可用的内容)
🎨 浏览器渲染
用户看到页面框架和骨架屏
📤 第三块 (Chunk 3)
Suspense 组件的数据就绪,发送真实 HTML
✨ 自动替换
React 自动用真实内容替换骨架屏
HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked X-Powered-By: Next.js <!-- 数据会分多次传输,而不是一次性 -->
1. 标记 Suspense 边界:React 遇到 <Suspense> 时, 会在 HTML 中插入特殊注释标记(如 $?)
2. 发送 Fallback:先发送 fallback 内容(骨架屏), 让用户立即看到页面
3. 后台处理:服务器继续等待 async 组件完成数据获取
4. 发送更新:数据就绪后,通过新的 chunk 发送真实内容和替换脚本
5. 客户端 Hydration:React 在客户端执行脚本,用真实内容替换 fallback
<!-- Chunk 1: 立即发送 -->
<!DOCTYPE html>
<html>
<head>
<script>/* React 运行时 */</script>
</head>
<body>
<div id="root">
<header>立即显示的内容</header>
<!-- Suspense 边界标记 -->
<!--$?-->
<template id="B:0"></template>
<!-- Fallback 内容(骨架屏) -->
<div class="loading-skeleton">
加载中...
</div>
<!--/$-->
<footer>页脚</footer>
</div>
<!-- Chunk 2: 500ms 后数据就绪,发送 -->
<div hidden id="S:0">
<!-- 真实的组件内容 -->
<div class="user-data">
<h3>用户数据</h3>
<p>张三 - zhangsan@example.com</p>
</div>
</div>
<script>
// React 的替换函数
$RC = function(id, html) {
// 找到 template 标记
const template = document.getElementById(id);
// 用真实内容替换 fallback
template.parentNode.replaceChild(
document.getElementById('S:0').firstChild,
template.nextSibling
);
};
$RC("B:0");
</script>
</body>
</html>❌ 传统 SSR
✅ 流式 SSR
* TTFB: Time to First Byte | FCP: First Contentful Paint | LCP: Largest Contentful Paint
尽可能使用服务端组件,只在需要交互时才使用 "use client"。这样可以减少客户端 JavaScript 包大小,提升性能。
用 Suspense 包裹慢速组件,避免阻塞整个页面渲染:
// ✅ 好的做法 - 流式渲染
import { Suspense } from 'react';
function Page() {
return (
<>
<FastComponent /> {/* 立即显示 */}
<Suspense fallback={<Loading />}>
<SlowComponent /> {/* 异步加载 */}
</Suspense>
</>
);
}
// ❌ 不好的做法 - 阻塞渲染
async function Page() {
const data = await fetchSlowData(); // 阻塞!
return <div>{data}</div>;
}将 "use client" 放在组件树的叶子节点,而不是根节点。例如:
// ✅ 好的做法
function Page() {
return (
<div>
<ServerComponent /> {/* Server */}
<InteractiveButton /> {/* Client */}
</div>
);
}
// ❌ 不好的做法
"use client";
function Page() { // 整个页面都变成 Client
return <div>...</div>;
}在服务端组件中直接获取数据,避免额外的 API 请求。可以使用 async/await 直接访问数据库或 API。
服务端组件可以嵌入客户端组件,但客户端组件不能直接导入服务端组件。如需传递,请使用 children prop。
1. 默认 SSR: Next.js App Router 中,所有组件默认在服务端渲染
2. async/await: 服务端组件可以直接使用 async 函数获取数据
3. 动态渲染: 页面每次请求都会重新渲染,刷新页面可看到数据更新
4. 服务端专属: 可以使用 process、fs 等 Node.js API
5. 查看源码: 右键"查看网页源代码"可看到完整的 HTML 内容
2026-01-09T15:05:21.822Z
此时间在服务端生成,刷新页面会更新
1234
总用户数
567
活跃用户
23
今日新增
张三
zhangsan@example.com
李四
lisi@example.com
王五
wangwu@example.com