Skip to content

常见疑问(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 = 客户端组件