React Server Components (RSC)
#react
目录
总结
- React Server Components (RSC):
- 服务器上运行的 React 组件
- 一切不需要交互的内容都应当放到服务端
- 比如 markdown
- 三种组件类型
- 默认:服务端组件
- 客户端组件:
- 使用
'use client';
标识
- 使用
- 共享组件
- 可在服务端和客户端都能使用的组件
- 区别
- 服务器组件限制:
- 不能使用 useState、useEffect 等客户端 hooks
- 不能访问浏览器 API
- 不能添加事件处理器
- 客户端组件限制:
- 不能直接导入服务器组件
- 需要通过 props 接收服务器组件
- 数据获取注意事项:
- 服务器组件中可以直接使用 async/await
- 客户端组件需要使用传统的数据获取方式
- 服务器组件不能使用像
useState
和useEffect
这样的 React hook;客户端则可以 - 服务器组件无权访问浏览器 API;客户端有完整的浏览器 API 权限;
- 服务端有权限直接访问服务端程序和 API;而客户端组件只能通过请求访问部分程序。
- 服务器组件限制:
UI = f(data, state)
- 客户端组件的工作是
UI = f(state)
- 服务端组件的工作是
UI = f(data)
- React 希望组合二者的优势,实现
UI = f(data, state)
- 客户端组件的工作是
1. RSC 基本概念
React Server Components 允许开发者编写在服务器上运行的 React 组件,这些组件可以:
- 直接访问服务器资源(数据库、文件系统等)
- 减少客户端 JavaScript 包大小
- 保持良好的交互性
RSC 每次预渲染后把 HTML 发送到客户端,由客户端进行水合(hydrate)并正式渲染。
这种做法的好处是,一部分原本要打包在客户端 JavaScript 文件里的代码,现在可以放在服务端运行了,从而减轻客户端的负担,提升应用的整体性能和响应速度。
React 19 带来了 RSC 的稳定版本,主要特性包括:
- 稳定性提升:RSC 在 React 19 中被标记为稳定特性
- 性能优化:通过预取机制提升客户端更新速度
- 更好的开发者体验:改进了错误处理和调试功能
2. 一切不需要交互的内容都应当放到服务端?
比如 markdown 渲染就很适合
// 客户端组件渲染
import marked from 'marked'; // 35.9K (11.2K gzipped)
import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)
function NoteWithMarkdown({text}) {
const html = sanitizeHtml(marked(text));
return (/* 渲染 */);
}
// 服务器组件渲染
import marked from 'marked'; // 零打包大小
import sanitizeHtml from 'sanitize-html'; // 零打包大小
function NoteWithMarkdown({text}) {
// 与之前相同
}
3. 三种组件类型
3.1. 服务器组件 (默认)
// 1. 服务器组件 (默认)
// 文件: app/page.js
async function ServerComponent() {
const data = await fetch('api/data');
return <div>{data}</div>;
}
3.2. 客户端组件
// 2. 客户端组件
// 文件: components/client.js
'use client';
function ClientComponent() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
3.3. 共享组件
// 3. 共享组件
// 可在服务端和客户端都能使用的组件
function SharedComponent({ children }) {
return <div className="shared">{children}</div>;
}
3.4. 主要区别
- 服务器组件限制:
- 不能使用 useState、useEffect 等客户端 hooks
- 不能访问浏览器 API
- 不能添加事件处理器
- 客户端组件限制:
- 不能直接导入服务器组件
- 需要通过 props 接收服务器组件
- 数据获取注意事项:
- 服务器组件中可以直接使用 async/await
- 客户端组件需要使用传统的数据获取方式
- 服务器组件不能使用像
useState
和useEffect
这样的 React hook;客户端则可以 - 服务器组件无权访问浏览器 API;客户端有完整的浏览器 API 权限;
- 服务端有权限直接访问服务端程序和 API;而客户端组件只能通过请求访问部分程序。
UI = f(data, state)
- 客户端组件的工作是
UI = f(state)
- 服务端组件的工作是
UI = f(data)
- React 希望组合二者的优势,实现
UI = f(data, state)
- 客户端组件的工作是
4. CSS 处理
4.1. 服务器组件中的 CSS
- 支持 CSS Modules
- 支持全局 CSS 导入
- 支持 CSS-in-JS 的静态部分
4.2. 客户端组件中的 CSS
- 支持所有传统的 CSS 方案
- 动态样式需要在客户端组件中处理
5. Remix 与 Next.js
- 当前 React 更新缓慢,反而是两个上层框架 Remix(由 Shopify 资助)和 Next.js(由 Vercel 资助)在激烈竞争。
6. 简单示例
// 1. 服务器端
async function BlogPost({ id }) {
// 直接访问数据库
const post = await db.posts.findById(id);
const author = await db.users.findById(post.authorId);
return (
<article>
<h1>{post.title}</h1>
<AuthorInfo author={author} />
{/* 客户端组件处理交互 */}
<ClientLikeButton initialLikes={post.likes} />
</article>
);
}
// 2. 客户端组件
'use client';
function ClientLikeButton({ initialLikes }) {
const [likes, setLikes] = useState(initialLikes);
return (
<button onClick={() => setLikes(likes + 1)}>
Like ({likes})
</button>
);
}