楼层: 首页/ 软件技术/ 前端进阶/ 第 2 章 SSR 与全栈:Next.js 15/16
全

第 2 章 SSR 与全栈:Next.js 15/16

Next.js 15 — App Router, Server Components

纯 SPA(Create React App / Vite)有两个毛病:① 首屏白屏——浏览器要先下 JS,再执行,再画 DOM,慢;② SEO 差——爬虫看到的是一个空 div。Next.js 是 Vercel 出的 React 全栈框架,在服务端就把 HTML 渲染好发给浏览器,同时能写后端 API。当前最新稳定版是 Next.js 16(15 仍是广泛使用的稳定线,升级前读官方 Upgrade Guide)。

念Next.js 核心心智

App Router(当前标准):用文件夹结构定义路由,app/page.tsx 就是首页,app/users/page.tsx 就是 /users。

Server Components:默认组件在服务端跑,直接访问数据库,不下发到浏览器,包体小、性能好。需要交互的组件加 "use client" 标记成客户端组件。

数据获取:服务端组件里直接 async/await 查库,不用写 API 请求。

app/page.tsx —— 服务端组件,直接查数据库

app/page.tsx —— 服务端组件,直接查数据库

// 默认就是服务端组件:在 Node 服务端跑 async function HomePage() { // 直接 await 拿数据,不用 fetch API const posts = await db.posts.findMany({ take: 10 }); return ( <main> <h1>最新文章</h1> {posts.map(p => <article key={p.id}>{p.title}</article>)} </main> ); }

app/users/[id]/page.tsx —— 动态路由

export default async function UserPage({ params }: { params: { id: string } }) { const user = await db.users.find(params.id); return <h1>{user.name}</h1>; }

需要交互的组件:标 "use client"

"use client"; // 这一行告诉 Next:这个组件下发到浏览器跑 import { useState } from "react"; export function LikeButton() { const [liked, setLiked] = useState(false); return <button onClick={() => setLiked(!liked)}> {liked ? "已赞" : "点赞"} </button>; }

四种渲染模式怎么选

模式什么时候用
SSG 静态生成构建时就生成 HTML,博客、文档、营销页。最快。
ISR 增量再生静态页面定时后台重新生成。电商商品页常用。
SSR 服务端渲染每次请求都在服务端现渲染。个性化内容、Dashboard。
CSR 客户端渲染同 SPA。后台管理系统这种不需要 SEO 的内部工具。

其他全栈/静态方案:Astro(内容站首选,零 JS 默认,岛屿架构)、Remix(Web 标准)、Gatsby(老一代 SSG)。营销/博客站选 Astro,复杂应用选 Next.js。

App Router 文件路由:文件名就是路由

文件作用
app/page.tsx路由页面(首页 /)。
app/layout.tsx布局,可嵌套,必须含 <html><body>。
app/loading.tsx加载状态(Suspense fallback)。
app/error.tsx错误边界(必须是客户端组件)。
app/not-found.tsx404 页。
app/route.tsAPI 路由(GET/POST/PUT/DELETE)。
app/blog/[slug]/page.tsx动态路由,params.slug 取参数。
app/shop/[...slug]/page.tsx捕获所有路由。
app/(group)/page.tsx路由组(不影响 URL)。

RSC:服务端组件与客户端组件

RRSC 心智模型

Server Component(默认):在服务端跑,直接查数据库、读文件系统、读密钥,不发一行 JS 到浏览器。不能用 useState/useEffect/事件/浏览器 API。

Client Component:文件顶部加 "use client",下发到浏览器跑,能用 useState/事件。服务端组件可以 import 客户端组件,反过来不行。数据获取尽量放服务端组件。

Server Actions:前端直接调后端函数(不用写 API 路由)

// app/actions.ts —— "use server" 标记整个文件是服务端动作 "use server"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; export async function createPost(formData: FormData) { await db.posts.create({ data: { title: formData.get("title") } }); revalidatePath("/blog"); // 重新验证列表页缓存 redirect("/blog"); } // 表单里直接当 action 用,不用写 onClick/fetch // <form action={createPost}><input name="title"/><button>发布</button></form>

Next.js 15 缓存新模型与渲染模式

Next 15 最大的坑:fetch 默认不缓存

15 起 fetch 默认 no-store(每次请求都拉最新)。要缓存得显式:fetch(url, { cache: 'force-cache' }) 或 next: { revalidate: 60, tags: ['posts'] }。配合 revalidateTag('posts') 精准失效。动态 API 路由里用了 cookies()/headers(),整个路由自动变动态。

渲染模式说明与选择
SSG 静态生成构建时出 HTML。博客、文档、营销页。最快。
ISR 增量再生revalidate 时间到了后台重新生成。商品页、内容站。
SSR 服务端渲染每次请求现渲染。个性化 Dashboard、需登录数据。
PPR 部分预渲染静态壳 + 动态洞,15 起更稳定。混合静态与个性化。
CSR 客户端渲染同 SPA。内部后台工具、不需 SEO。

元数据、图片、中间件

// app/layout.tsx —— 元数据 API,自动生成 SEO 头 export const metadata = { title: "我的博客", description: "全栈学习笔记", openGraph: { title: "我的博客", type: "website" }, }; // 动态页用 generateMetadata({ params }) 按文章生成标题描述 // next/image:自动 WebP/AVIF、懒加载、响应式 srcset、防 CLS import Image from "next/image"; <Image src="/me.png" width={800} height={600} alt="我" placeholder="blur" /> // 远程图片要在 next.config.js 配 images.remotePatterns // middleware.ts:鉴权、A/B 测试、路径重写 import { NextResponse } from "next/server"; export function middleware(req) { if (!req.cookies.get("token")) return NextResponse.redirect(new URL("/login", req.url)); return NextResponse.next(); } export const config = { matcher: ["/admin/:path*"] };

部署与常见坑

Next.js 就是 Vercel 亲儿子,Git 一连 push 就自动部署,Serverless Functions / Edge / ISR / Image Optimization 全免配置。自托管用 output: 'standalone' 多阶段 Docker 构建,或 Node server + PM2 + Nginx 反代。环境变量只有 NEXT_PUBLIC_ 前缀才会打进客户端。

本章面试题

Q1. App Router 里什么时候必须加 "use client"?

看答案

只要用 useState/useEffect/事件处理/浏览器 API(window/document/localStorage)就得加。纯展示、只 await 数据的组件保持服务端组件,包体更小。

Q2. SSR、SSG、ISR 区别?

看答案

SSG 构建时生成一次静态 HTML;ISR 生成后按 revalidate 时间后台增量更新;SSR 每次请求都在服务端现渲染。内容站 SSG/ISR,个性化页 SSR。

Q3. Next 15 的缓存和以前有什么不同?

看答案

以前 fetch 默认缓存;15 起默认不缓存(no-store),要缓存必须显式 force-cache 或 next.revalidate/tags,再用 revalidateTag/revalidatePath 失效。

Q4. Server Actions 是什么?

看答案

标了 "use server" 的异步函数,能直接在表单 action 里调用,前端不用写 fetch/API 路由,服务端跑完直接 revalidatePath 刷新数据。