React Server Components (RSC) 与 App Router 简介:Next.js 的未来范式

发布于:2025-09-15 ⋅ 阅读:(31) ⋅ 点赞:(0)

React Server Components (RSC) 与 App Router 简介:Next.js 的未来范式

作者:码力无边


在过去的十八篇文章中,我们已经深入掌握了 Next.js 的 pages 目录(Pages Router)模型。我们学会了如何使用 getStaticProps, getServerSideProps 等数据获取函数,以及如何构建 API 路由和中间件。这是一个成熟、稳定且强大的模型,支撑了无数生产级应用。

然而,Web 开发的世界永远在进化。为了追求更优的性能、更佳的开发体验和更灵活的架构,React 核心团队与 Next.js 团队 (Vercel) 联手,推出了一项堪称革命性的新特性——React Server Components (RSC),并围绕它构建了全新的路由和渲染模型:App Router

从 Next.js 13 开始,App Router 成为了推荐的开发方式(pages 目录依然完全支持)。理解这个新范式,不仅是跟上 Next.js 的发展,更是洞察整个前端开发未来的关键。本文将为你揭开 RSC 和 App Router 的神秘面纱,解释它们是什么,以及它们带来了哪些颠覆性的优势。

回顾过去:pages 目录的局限性

在我们拥抱未来之前,先要理解它解决了过去的什么问题。pages 目录模型虽然优秀,但存在一些固有的局限性:

  1. 数据获取的“全有或全无”:在一个页面中,你只能选择一种主要的数据获取策略(SSG 或 SSR)。如果页面上的大部分内容是静态的,但有一个小组件需要动态数据,你往往不得不让整个页面都采用 SSR (getServerSideProps),从而牺牲了性能。
  2. 客户端 JavaScript 的瀑布流:在 pages 目录中,一个路由下的所有组件代码,最终都会被打包发送到客户端(即使它们是在服务器上预渲染的)。当组件树变得庞大时,客户端需要下载和解析的 JavaScript 也会随之增多。
  3. 布局(Layouts)的实现不够原生:虽然我们通过 _app.tsxgetLayout 模式实现了布局,但这更像是一种“变通方案 (workaround)”,而不是框架原生支持的一等公民。

新范式:React Server Components (RSC)

RSC 是理解 App Router 的核心。它引入了一种全新的组件类型,从根本上改变了我们对“组件”的认知。

在此之前,我们所写的所有 React 组件,无论是否经过 SSR/SSG,最终都会在客户端“激活”(hydrate),成为客户端组件 (Client Components)。它们可以使用状态 (useState)、生命周期 (useEffect),并响应用户交互。

React Server Components 是一种只在服务器上运行、且永远不会被发送到客户端的组件。

Server Components 的超能力

  1. 直接访问后端资源:由于它们只在服务器上运行,Server Components 可以像你的后端代码一样,直接、安全地访问数据库、文件系统、内部服务或使用私有环境变量。你不再需要为了获取数据而创建一个专门的 API 路由。

    // app/page.tsx (这是一个 Server Component)
    import { db } from '@/lib/db'; // 直接导入数据库实例
    
    async function getPosts() {
      // 直接进行数据库查询
      return await db.post.findMany();
    }
    
    export default async function HomePage() {
      const posts = await getPosts();
      
      return (
        <main>
          {posts.map(post => <PostItem key={post.id} post={post} />)}
        </main>
      );
    }
    

    注意到这里的 async/await 了吗?Server Components 可以是 async 函数!这使得数据获取变得前所未有的直观。

  2. 零客户端 JavaScript:Server Components 的代码及其所有依赖(包括大型库,如 marked 用于解析 Markdown)都不会被打包进客户端的 JavaScript bundle 中。它们在服务器上渲染成一种特殊的中间格式,然后流式传输到客户端。这能极大地减小客户端 JavaScript 的体积,显著提升应用的初始加载性能。

  3. 自动代码分割:每个 Server Component 都可以被看作是一个代码分割点,实现了组件级别的代码分割。

客户端组件 (Client Components)

当然,我们仍然需要能够响应用户交互、使用状态和生命周期的组件。在 App Router 中,这类组件被称为客户端组件 (Client Components)

你需要通过在文件顶部添加一个 "use client"; 指令来明确地将一个组件标记为客户端组件。

// components/Counter.tsx
"use client"; // 标记为客户端组件

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      You clicked {count} times
    </button>
  );
}

重要规则

  • 默认情况下,App Router (app 目录) 中的所有组件都是 Server Components
  • 只有需要使用 React Hooks(如 useState, useEffect)或浏览器 API(如 window)时,才需要使用 "use client"; 将其标记为客户端组件。

App Router:为 RSC 量身打造的路由系统

App Router 是一个基于 RSC 构建的全新路由系统,它位于项目的 app 目录中。

核心特性:

  1. 默认 Server Components:如上所述,app 目录下的组件默认都是 Server Components,鼓励你将尽可能多的逻辑保留在服务器端。
  2. 原生支持布局 (Layouts):App Router 将布局提升为一等公民。你可以在任何目录下创建一个 layout.tsx 文件,它会自动包裹该目录及其所有子目录下的页面。这使得创建复杂的嵌套布局变得极其简单和直观。
  3. 组件化的数据获取:数据获取不再局限于页面级别。任何一个 Server Component 都可以独立地获取自己的数据。这解决了 pages 目录中“全有或全无”的问题,让数据获取更加精细化。
  4. 流式渲染 (Streaming):App Router 与 React Suspense 深度集成,支持服务端流式渲染。服务器可以先快速发送页面的静态部分(如布局),然后随着 Server Components 数据获取的完成,逐步将内容“流”到客户端 UI 中,用户可以更快地看到页面的部分内容,而不是等待整个页面加载完成。

app 目录结构示例

app/
├── layout.tsx        # 根布局
├── page.tsx          # 首页 (/)
├── dashboard/
│   ├── layout.tsx    # Dashboard 区域的专属布局
│   ├── page.tsx      # /dashboard 页
│   └── settings/
│       ├── page.tsx  # /dashboard/settings 页
└── ...

这种结构比 pages 目录更具表现力和组织性。

总结:一次思维的转变

从 Pages Router 迁移到 App Router,不仅仅是学习一套新的 API,更是一次思维模式的深刻转变

传统思维 (Pages Router) 新范式思维 (App Router)
组件默认在客户端运行。 组件默认在服务器运行。
数据获取在页面级别进行。 数据获取在组件级别进行。
整个页面的 JS 被发送到客户端。 只有客户端组件的 JS 被发送。
布局是“变通方案”。 布局是原生一等公民

React Server Components 和 App Router 代表了 React 和 Next.js 的未来。它们通过将更多的计算工作移回服务器,并以更智能的方式向客户端交付内容,旨在从根本上解决现代 Web 应用面临的性能和复杂性挑战。

这只是一个开始。在接下来的文章中,我们将深入探讨 App Router 和 Pages Router 的具体差异和选择考量,并逐步学习如何在 App Router 中进行数据获取、状态管理和构建复杂的应用。这次范式转移是激动人心的,让我们一起拥抱它!