Next.js 全栈框架
一句话概述:Next.js 是基于React的全栈Web框架,由Vercel开发,提供服务端渲染(SSR)、静态生成(SSG)、API路由等开箱即用的功能。
核心知识点表
| 概念 | 白话解释 |
|---|
| App Router | Next.js 13+的路由系统,用文件夹结构定义页面路由 |
| Server Component | 服务端组件,在服务器上渲染,不发JavaScript到浏览器 |
| Client Component | 客户端组件,在浏览器运行,需要交互的组件用这个 |
| Server Action | 在组件里直接写服务端函数,不需要单独建API |
| SSR | 服务端渲染,每次请求时在服务器生成HTML |
| SSG | 静态生成,构建时生成HTML,最快 |
| ISR | 增量静态再生,定时更新静态页面 |
| PPR | 部分预渲染(Partial Prerendering),静态壳+动态流 |
| Middleware | 中间件,在请求到达页面之前执行逻辑(鉴权等) |
| Turbopack | 替代Webpack的新打包器,极快 |
版本信息(2026年5月)
- Next.js 16(2025年10月发布,当前最新大版本)
- React 19 支持、React Compiler稳定、PPR接近GA
- Turbopack生产构建已稳定
安装配置
# 创建Next.js项目(推荐方式)
npx create-next-app@latest my-app # 交互式创建
# 选项建议:
# TypeScript → Yes
# ESLint → Yes
# Tailwind CSS → Yes
# src/ directory → Yes
# App Router → Yes(推荐)
# Turbopack → Yes(新项目推荐)
cd my-app # 进入项目
# 启动开发服务器
npm run dev # 访问 http://localhost:3000
项目结构(App Router)
my-app/
├── src/
│ ├── app/ # App Router目录
│ │ ├── layout.tsx # 根布局(所有页面共享)
│ │ ├── page.tsx # 首页 → /
│ │ ├── about/
│ │ │ └── page.tsx # 关于页 → /about
│ │ ├── blog/
│ │ │ ├── page.tsx # 博客列表 → /blog
│ │ │ └── [slug]/
│ │ │ └── page.tsx # 博客详情 → /blog/xxx
│ │ ├── api/
│ │ │ └── users/
│ │ │ └── route.ts # API路由 → /api/users
│ │ └── globals.css # 全局样式
│ └── components/ # 可复用组件
├── public/ # 静态资源
├── next.config.ts # Next.js配置
└── package.json
基本使用
页面和布局
// src/app/layout.tsx — 根布局
export default function RootLayout({
children, // 子页面内容
}: {
children: React.ReactNode
}) {
return (
<html lang="zh">
<body>
<nav>导航栏</nav> {/* 所有页面都有的导航 */}
{children} {/* 这里放具体页面内容 */}
<footer>底部</footer>
</body>
</html>
)
}
// src/app/page.tsx — 首页(默认是Server Component)
export default function HomePage() {
return (
<main>
<h1>欢迎来到我的网站</h1>
<p>这是一个Server Component,在服务器上渲染</p>
</main>
)
}
Server Component(服务端组件)
// src/app/users/page.tsx
// 默认就是Server Component,可以直接查数据库!
async function getUsers() {
// 直接在组件里查数据库或调API
const res = await fetch('https://api.example.com/users')
return res.json()
}
export default async function UsersPage() {
const users = await getUsers() // 服务端执行,不暴露给浏览器
return (
<ul>
{users.map((user: any) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
Client Component(客户端组件)
// src/components/Counter.tsx
'use client' // 加这行声明为客户端组件
import { useState } from 'react' // 客户端才能用hooks
export default function Counter() {
const [count, setCount] = useState(0) // 状态管理
return (
<div>
<p>计数: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}
Server Action
// src/app/contact/page.tsx
// Server Action:在组件里直接写服务端逻辑
export default function ContactPage() {
// 这个函数在服务器上执行!
async function submitForm(formData: FormData) {
'use server' // 标记为Server Action
const name = formData.get('name') as string
const email = formData.get('email') as string
// 直接操作数据库
// await db.insert({ name, email })
console.log(`收到: ${name}, ${email}`)
}
return (
<form action={submitForm}>
<input name="name" placeholder="姓名" required />
<input name="email" type="email" placeholder="邮箱" required />
<button type="submit">提交</button>
</form>
)
}
API路由
// src/app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server'
// GET /api/users
export async function GET() {
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
]
return NextResponse.json(users) // 返回JSON
}
// POST /api/users
export async function POST(request: NextRequest) {
const body = await request.json() // 解析请求体
// 保存到数据库...
return NextResponse.json(
{ message: '创建成功', data: body },
{ status: 201 }
)
}
高级用法
动态路由
// src/app/blog/[slug]/page.tsx
// [slug] 是动态参数,匹配 /blog/xxx
type Props = {
params: Promise<{ slug: string }>
}
export default async function BlogPost({ params }: Props) {
const { slug } = await params // 获取URL参数
const post = await fetch(`https://api.example.com/posts/${slug}`).then(r => r.json())
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
)
}
// 静态生成:构建时预生成所有博客页面
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return posts.map((post: any) => ({
slug: post.slug, // 返回所有可能的slug值
}))
}
Middleware中间件
// src/middleware.ts(根目录)
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// 检查是否登录
const token = request.cookies.get('token')
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
// 未登录访问dashboard,重定向到登录页
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next() // 继续处理请求
}
// 配置中间件生效的路径
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*'],
}
数据缓存与重验证
// 缓存策略
const data1 = await fetch(url) // 默认缓存(静态)
const data2 = await fetch(url, { cache: 'no-store' }) // 不缓存(动态)
const data3 = await fetch(url, { next: { revalidate: 60 } }) // 60秒后重新验证
常见报错与解决
| 报错信息 | 原因 | 解决方案 |
|---|
useState is not allowed in Server Components | 在Server Component里用了hooks | 加'use client'声明为Client Component |
Error: Dynamic server usage | 在静态页面中使用了动态函数 | 用export const dynamic = 'force-dynamic' |
Module not found | 包没安装或路径错误 | npm install xxx或检查import路径 |
Hydration mismatch | 服务端和客户端渲染结果不同 | 检查是否有依赖浏览器API的代码 |
NEXT_REDIRECT | redirect()在错误上下文中调用 | 在Server Action或Server Component中使用 |
速查表
# ===== CLI命令 =====
npx create-next-app@latest # 创建项目
npm run dev # 开发模式
npm run build # 构建
npm run start # 生产模式启动
npm run lint # 代码检查
# ===== 文件路由约定 =====
# page.tsx 页面组件
# layout.tsx 布局(嵌套)
# loading.tsx 加载UI
# error.tsx 错误UI
# not-found.tsx 404页面
# route.ts API路由
# middleware.ts 中间件
# ===== 特殊导出 =====
# export const dynamic = 'force-dynamic' // 强制动态渲染
# export const revalidate = 60 // ISR: 60秒重验证
# export async function generateStaticParams() // 静态路径
# export async function generateMetadata() // SEO元数据
同类工具对比
| 特性 | Next.js | Nuxt | SvelteKit | Astro | Remix |
|---|
| 基于 | React | Vue | Svelte | 多框架 | React |
| SSR | 支持 | 支持 | 支持 | 支持 | 支持 |
| SSG | 支持 | 支持 | 支持 | 默认 | 有限 |
| 生态 | 最大 | Vue生态 | 增长中 | 丰富 | React |
| 学习曲线 | 中等 | 较低 | 较低 | 低 | 中等 |
| 适合 | 全栈应用 | Vue项目 | 高性能应用 | 内容站 | 复杂交互 |
面试建议:Next.js是React全栈开发的首选。面试重点:1)Server Component vs Client Component的区别和使用场景;2)SSR/SSG/ISR的区别;3)App Router vs Pages Router;4)Server Action简化了什么。