常见疑问(FAQ)
Next.js 13+ 引入 App Router 后的变化
服务器组件 vs 客户端组件
✅ 服务器组件(默认)
- 默认情况下,Next.js 的组件都是服务器组件。
- 只在服务端运行,不会被打包到客户端 JS bundle 中。
- 可以直接访问数据库、环境变量、文件系统等敏感信息。
- 不能使用 React hooks(如 useState、useEffect),也不能绑定事件处理函数(如 onClick)。
✅ 客户端组件
- 必须在文件顶部添加 "use client" 指令。
- 会在客户端 hydration(水合)后运行,可以使用交互逻辑(hooks、事件等)。
- 不能直接访问服务端资源(比如 process.env.SECRET_KEY),因为代码会暴露给浏览器。
SSG ? SSR ? CSR ?
什么时候是服务器渲染(SSR)?什么时候是客户端渲染(CSR)?
- Next.js 的渲染模型其实更准确地说是:混合渲染(Hybrid Rendering)
| 渲染方式 | 触发时机 | 特点 |
|---|---|---|
| 静态生成(SSG) | 构建时(build time) | 页面 HTML 预先生成,速度快,适合内容不变的页面(如博客文章)。 |
| 服务端渲染(SSR) | 每次请求时 | 页面在服务端动态生成 HTML,适合个性化或实时数据(如用户仪表盘)。 |
| 客户端渲染(CSR) | 浏览器加载后 | 仅用于交互部分(如弹窗、表单),初始 HTML 可能是空的或骨架屏。 |
text
💡注意:服务器组件 ≠ SSR。
服务器组件可以在 SSG 或 SSR 中使用。
即使是静态生成的页面,也可以包含服务器组件(在构建时执行)。服务端和页面逻辑写在一起安全吗?
这取决于你怎么“写在一起”。 一般来说,把服务端逻辑和页面逻辑写在一起是安全的,因为 Next.js 会在构建时将服务器组件代码排除在客户端 JS bundle 之外。
✅ 安全的做法:
- 把敏感逻辑(数据库查询、API 密钥)放在服务器组件或 API Routes 中。
- 服务器组件天然不会把代码发送到客户端,所以是安全的。
- 使用 async/await 直接在服务器组件中获取数据(无需 useEffect + fetch)。
tsx
// app/page.tsx —— 服务器组件(默认)
export default async function HomePage() {
const data = await db.query('SELECT * FROM users'); // 安全!只在服务端运行
return <div>{data.name}</div>;
}❌ 不安全的做法:
- 在客户端组件中硬编码密钥、直接调用内部 API。
- 把服务器逻辑“复制”到客户端组件里。
tsx
// app/page.tsx —— 客户端组件
'use client';
// ❌ 危险!会被打包到浏览器
"use client";
import { useEffect } from 'react';
export default function BadComponent() {
useEffect(() => {
// 这个 fetch 会被浏览器执行,如果 API 没有鉴权就可能泄露数据
fetch('/api/internal-data');
}, []);
}最佳实践建议
- 默认使用服务器组件,除非需要交互(状态、事件、useEffect 等)。
- 敏感数据和逻辑永远留在服务端(服务器组件或 API Routes)。
- 如果需要在客户端显示动态数据:
- 要么通过服务器组件直接传 props(推荐);
- 要么客户端组件调用受保护的 API(需身份验证)。
- 使用 loading.tsx、error.tsx 等提升用户体验,而不需要手动 loading 状态(除非复杂交互)。
总结
- 服务器组件 = 安全、高效、无交互;
- 客户端组件 = 交互强、需谨慎暴露逻辑。
- 两者配合使用,各司其职,才是 Next.js 的最佳姿势。
- 关键在于 是否添加 "use client" 指令
use client = 客户端组件