首页 / Next.js 16 入门教程 / Server Components

Next.js 16 入门教程

Server Components

本教程共 42 篇 · 第 6 篇 · 更新于 2026-07-30 · 约 7 分钟阅读

Next.jsNext.js 16 入门教程Server Components服务端组件RSC

6. Server Components

本节目标:理解 Server Components 是什么、为什么需要它、它的限制,以及何时使用它。

为什么需要 Server Components

传统 React 应用是客户端渲染——浏览器下载 JS 包,执行 React 代码,生成 DOM。这带来三个问题:

  1. 首屏慢:得等 JS 下载执行完,用户才看到内容
  2. 包体积大:所有组件代码(包括只在服务端用的)都发给浏览器
  3. 数据获取复杂:用 useEffect 取数据,有瀑布请求问题

Server Components 让组件在服务器上执行,只把渲染结果(HTML + RSC Payload)发给客户端。

什么是 Server Components

Server Components 是 React 18+ 的新特性。在 Next.js App Router 中,所有组件默认都是 Server Components

// 这就是一个 Server Component
// app/posts/page.tsx
export default async function Page() {
  const posts = await db.post.findMany()

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

这个组件:

  • 在服务器上执行
  • 可以直接访问数据库
  • 可以用 async/await 获取数据
  • 不发送 JS 到客户端

Server Components 的优势

1. 直接访问后端资源

// 可以直接查数据库
const users = await db.query('SELECT * FROM users')

// 可以直接读文件
const content = fs.readFileSync('./data.json', 'utf-8')

这些代码永远不会出现在客户端包里,密钥、密码不会泄露。

2. 更小的客户端包

Server Component 的代码不需要下载到浏览器。这意味着:

  • 页面加载更快
  • 首屏渲染更快(直接显示 HTML)
  • 低端设备更友好

3. 更好的数据获取

Server Components 支持 async/await,没有 useEffect 的瀑布问题:

// 并行请求(没有 waterfall)
export default async function Page() {
  const users = getUsers()
  const posts = getPosts()

  const [usersData, postsData] = await Promise.all([users, posts])

  return <div>...</div>
}

4. 更好的 SEO

HTML 直接在服务器生成,搜索引擎能完整抓取内容。

Server Components 的限制

Server Components 不是万能的,有几个硬性限制:

不能用 useState / useEffect

Server Components 在服务器上运行一次就结束了,没有组件生命周期:

// ❌ 错误:Server Component 不能用 useState
export default function Page() {
  const [count, setCount] = useState(0) // 报错!
  return <div>{count}</div>
}

不能用浏览器 API

// ❌ 错误:没有 window、localStorage
export default function Page() {
  const width = window.innerWidth // 报错!
  const data = localStorage.getItem('key') // 报错!
}

不能用事件处理

// ❌ 错误:没有 onClick、onChange
export default function Page() {
  return <button onClick={() => alert('hi')}>点击</button>
}

不能用自定义 Hook(依赖状态的)

自定义 Hook 如果用了 useStateuseEffect,Server Component 也不能用。

什么时候用 Server Components

场景用 Server Component
获取数据
直接访问数据库
使用 API 密钥
渲染静态内容
需要 SEO
需要交互(点击、输入)
需要状态(useState)
需要生命周期(useEffect)
需要浏览器 API

Server 和 Client 如何协作

一个页面可以混用两种组件。典型的模式:

// Server Component:获取数据
import LikeButton from '@/components/like-button'
import { getPost } from '@/lib/data'

export default async function Page({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  const post = await getPost(id)

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
      {/* Client Component 处理交互 */}
      <LikeButton likes={post.likes} />
    </article>
  )
}
// Client Component:处理交互
'use client'

import { useState } from 'react'

export default function LikeButton({ likes }: { likes: number }) {
  const [count, setCount] = useState(likes)

  return (
    <button onClick={() => setCount(count + 1)}>
      赞 {count}
    </button>
  )
}

渲染流程

服务端

  1. Server Components 渲染为 RSC Payload(一种紧凑的二进制格式)
  2. Client Components 的位置用占位符标记
  3. 两者结合生成预渲染的 HTML

客户端(首次加载)

  1. HTML 立即显示非交互预览
  2. RSC Payload 用于协调组件树
  3. JS 下载后”注水”(hydrate)Client Components,让它们可交互

后续导航

  1. RSC Payload 被预取并缓存
  2. Client Components 完全在客户端渲染,不需要服务器 HTML

数据传输

Server Component 向 Client Component 传数据,通过 props:

// Server Component
const user = await getUser()
<ClientComponent user={user} />
Important

传给 Client Component 的 props 必须是可序列化的。函数、类实例不能直接传。

如果需要传函数,把函数定义为 Server Action(用 "use server" 标记)。

防止环境污染

有些代码只能在服务端运行(比如用 API 密钥的函数)。如果不小心在 Client Component 里导入,密钥会泄露。

Next.js 提供 server-only 包防止这种情况:

npm install server-only
// lib/data.ts
import 'server-only'

export async function getData() {
  const res = await fetch('https://api.example.com', {
    headers: { Authorization: process.env.API_KEY }
  })
  return res.json()
}

如果 Client Component 导入这个文件,构建时会报错。

小结

这一章我们理解了 Server Components:

  1. 默认是 Server Component,除非加 "use client"
  2. 优势:直连后端、小包、并行请求、SEO 友好
  3. 限制:不能用 state、effect、浏览器 API、事件处理
  4. 典型模式:Server 获取数据,Client 处理交互
  5. server-only 防止服务端代码泄露到客户端

下一章,我们来详细学习 Client Components。