📌 关于 Next.js: Next.js 是由 Vercel 开发的 React 全栈框架,支持服务端渲染(SSR)、静态站点生成(SSG)、增量静态再生成(ISR)等多种渲染模式。被世界上一些最大的公司使用,可创建高质量的 Web 应用程序。
📋 学习路线图
1
环境准备(1-2 天)
Node.js 18.17+、VS Code + React 扩展、包管理器(npm/pnpm/bun)
2
基础入门(3-5 天)
项目创建、目录结构、路由系统、组件开发
3
核心概念(5-7 天)
数据获取、缓存、服务端组件、客户端组件
4
进阶实战(7-10 天)
API 路由、中间件、认证系统、性能优化
5
项目实战(10-15 天)
完整项目开发、最佳实践、部署上线
🛠️ 第一步:环境准备
前置要求
- Node.js - 18.17 或更新版本(推荐使用 LTS 版本)
- 文本编辑器 - VS Code + React 扩展 或 WebStorm
- 终端 - 用于运行 Next.js 命令
- 包管理器 - npm / yarn / pnpm / bun(任选其一)
💡 推荐配置: 使用 pnpm 作为包管理器,速度更快、磁盘占用更少。安装命令:
npm install -g pnpm
📦 第二步:创建项目
1️⃣创建新项目
# 使用 npx (推荐)
npx create-next-app@latest <project-name>
# 使用 pnpm
pnpm create next-app@latest <project-name>
# 使用 bun
bunx create-next-app@latest <project-name>
2️⃣进入项目目录
cd <project-name>
3️⃣启动开发服务器
# 使用 npm
npm run dev
# 使用 pnpm
pnpm dev
# 使用 bun
bun run dev
开发服务器将在 http://localhost:3000 启动
📁 第三步:理解目录结构
| 目录/文件 | 作用 | 说明 |
|---|---|---|
app/ |
App Router 目录 | Next.js 13+ 推荐结构 |
app/page.tsx |
首页组件 | 路由 / 的页面 |
app/layout.tsx |
根布局 | 所有页面共享的布局 |
app/globals.css |
全局样式 | 全局 CSS 样式文件 |
components/ |
组件目录 | 可复用的 React 组件 |
lib/ |
工具库 | 工具函数、配置等 |
public/ |
静态资源 | 图片、字体等静态文件 |
next.config.ts |
配置文件 | Next.js 项目配置 |
package.json |
项目配置 | 依赖和脚本定义 |
⚡ 第四步:核心概念
1. App Router vs Pages Router
Next.js 13+ 推荐使用 App Router(基于 React Server Components):
💡 对比:
- App Router - 新一代路由系统,支持服务端组件、嵌套布局、并行路由
- Pages Router - 传统路由系统,基于文件的路由,简单易用
2. 服务端组件 vs 客户端组件
Next.js 的核心特性之一:
app/page.tsx - 服务端组件(默认)
// 服务端组件 - 默认
// 可以直接在服务端执行数据库查询、API 调用
export default async function Page() {
const data = await fetch('https://api.example.com/data')
return (
<main>
<h1>服务端渲染的内容</h1>
<p>{data.message}</p>
</main>
)
}
app/components/Counter.tsx - 客户端组件
'use client'
// 客户端组件 - 需要交互状态时使用
import { useState } from 'react'
export function Counter() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
)
}
💡 使用规则:
- 默认使用服务端组件(更好的性能、SEO)
- 需要 useState、useEffect、事件处理时,添加
'use client' - 服务端组件可以导入客户端组件,反之不行
3. 数据获取
Next.js 提供多种数据获取方式:
app/page.tsx - 服务端数据获取
// 服务端组件中直接异步获取数据
export default async function Page() {
// 自动缓存,可配置
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache' // 或 'no-store' 禁用缓存
})
return <div>{data.title}</div>
}
// 或使用 async/await 模式
async function getData() {
const res = await fetch('https://api.example.com/data')
return res.json()
}
export default async function Page() {
const data = await getData()
return <div>{data.title}</div>
}
4. 路由系统
基于文件系统的路由(App Router):
路由示例
app/
├── page.tsx → /
├── about/
│ └── page.tsx → /about
├── blog/
│ ├── page.tsx → /blog
│ └── [slug]/
│ └── page.tsx → /blog/:slug (动态路由)
├── dashboard/
│ ├── layout.tsx → 仪表盘布局
│ └── page.tsx → /dashboard
└── api/
└── route.ts → API 路由
5. 布局(Layouts)
在多个页面之间共享 UI:
app/layout.tsx - 根布局
export const metadata = {
title: 'My Next.js App',
description: 'Generated by Next.js',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="zh-CN">
<body>
<nav>
<a href="/">首页</a>
<a href="/about">关于</a>
<a href="/blog">博客</a>
</nav>
{children}
<footer>© 2026 My App</footer>
</body>
</html>
)
}
6. API 路由
在 Next.js 中创建 API 端点:
app/api/users/route.ts
import { NextResponse } from 'next/server'
// GET 请求
export async function GET() {
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
return NextResponse.json(users)
}
// POST 请求
export async function POST(request: Request) {
const body = await request.json()
// 处理创建用户的逻辑
const newUser = { id: 3, ...body }
return NextResponse.json(newUser, { status: 201 })
}
app/api/users/[id]/route.ts - 动态路由
import { NextResponse } from 'next/server'
// GET /api/users/1
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const { id } = params
// 根据 ID 获取用户
const user = { id, name: 'User ' + id }
return NextResponse.json(user)
}
// DELETE /api/users/1
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
const { id } = params
// 删除用户的逻辑
return NextResponse.json({ success: true })
}
7. 中间件(Middleware)
在请求到达页面之前运行代码:
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')) {
return NextResponse.redirect(new URL('/login', request.url))
}
// 添加自定义 header
const response = NextResponse.next()
response.headers.set('x-custom-header', 'value')
return response
}
// 配置中间件匹配的路径
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*']
}
🎯 第五步:实战项目 - 博客系统
项目结构
my-nextjs-blog/
├── app/
│ ├── blog/
│ │ ├── [slug]/
│ │ │ └── page.tsx # 博客详情页
│ │ └── page.tsx # 博客列表页
│ ├── about/
│ │ └── page.tsx # 关于页
│ ├── api/
│ │ └── posts/
│ │ └── route.ts # 博客 API
│ ├── components/
│ │ ├── BlogCard.tsx # 博客卡片
│ │ └── NavBar.tsx # 导航栏
│ ├── globals.css # 全局样式
│ ├── layout.tsx # 根布局
│ └── page.tsx # 首页
├── lib/
│ └── posts.ts # 博客数据工具
├── public/
│ └── images/ # 静态图片
└── next.config.ts # 配置文件
示例代码
lib/posts.ts
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
const postsDirectory = path.join(process.cwd(), 'posts')
export function getSortedPostsData() {
const fileNames = fs.readdirSync(postsDirectory)
const allPostsData = fileNames.map(fileName => {
const id = fileName.replace(/\.md$/, '')
const fullPath = path.join(postsDirectory, fileName)
const fileContents = fs.readFileSync(fullPath, 'utf8')
const { data } = matter(fileContents)
return {
id,
title: data.title,
date: data.date,
excerpt: data.excerpt
}
})
return allPostsData.sort((a, b) => {
return a.date > b.date ? -1 : 1
})
}
export function getPostData(id: string) {
const fullPath = path.join(postsDirectory, `${id}.md`)
const fileContents = fs.readFileSync(fullPath, 'utf8')
const { data, content } = matter(fileContents)
return {
id,
title: data.title,
date: data.date,
content
}
}
app/blog/page.tsx
import { getSortedPostsData } from '@/lib/posts'
import BlogCard from '@/components/BlogCard'
export default function BlogPage() {
const posts = getSortedPostsData()
return (
<main>
<h1>博客文章</h1>
<div className="grid">
{posts.map(post => (
<BlogCard key={post.id} post={post} />
))}
</div>
</main>
)
}
app/blog/[slug]/page.tsx
import { getPostData } from '@/lib/posts'
import { notFound } from 'next/navigation'
export default async function BlogPost({
params
}: {
params: { slug: string }
}) {
const post = getPostData(params.slug)
if (!post) {
notFound()
}
return (
<article>
<h1>{post.title}</h1>
<time>{post.date}</time>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
)
}
🚀 第六步:构建与部署
生产构建
# 构建项目
npm run build
# 启动生产服务器
npm run start
部署选项
- Vercel - 一键部署,Next.js 官方推荐(最简单)
- Netlify - 支持 Next.js 部署
- Docker - 容器化部署
- 传统服务器 - Node.js 进程托管
💡 推荐: 使用 Vercel 部署 Next.js 应用最简单,零配置自动部署。GitHub 仓库连接后自动构建和部署!
📚 学习资源
- 官方文档 - nextjs.org/docs
- 官方教程 - nextjs.org/learn
- GitHub 仓库 - vercel/next.js
- 示例项目 - next.js/examples
- 模板市场 - vercel.com/templates
✅ 学完本教程后,你将能够:
- ✅ 创建和配置 Next.js 项目
- ✅ 理解 App Router 和路由系统
- ✅ 掌握服务端组件和客户端组件
- ✅ 实现数据获取和缓存
- ✅ 开发 API 路由和中间件
- ✅ 构建并部署生产应用
📖 原文链接
本文档内容整理自 Next.js 官方文档:
📌
Next.js - The React Framework
由 Vercel 开发和维护 · 被世界顶级公司使用