📑 文章目录
Next.js 15是React生态中最受欢迎的全栈框架,它提供了服务端渲染、静态站点生成、API路由等强大功能。本教程将从零开始,带你掌握Next.js 15的核心概念和实战技巧。
快速开始
让我们从创建第一个Next.js 15项目开始。
创建项目
使用官方脚手架创建新项目:
# 使用yarn创建项目
yarn create next-app my-app
# 或使用npx
npx create-next-app@latest my-app
创建时配置选项
创建过程中会询问以下配置:
✔ Would you like to use ESLint? Yes
✔ Would you like to use Tailwind CSS? Yes
✔ Would you like to use `src/` directory? Yes
✔ Would you like to use App Router? Yes
✔ Would you like to customize the default import alias (@/*)? No
项目结构
Next.js 15的项目结构如下:
my-app/
├── app/
│ ├── layout.tsx # 根布局(所有页面共用)
│ ├── page.tsx # / - 首页
│ ├── about/
│ │ └── page.tsx # /about - 关于页面
│ └── blog/
│ └── [slug]/
│ └── page.tsx # /blog/[slug] - 动态路由
├── public/ # 静态资源
├── styles/ # 全局样式
├── package.json
└── next.config.js
运行开发服务器
npm install
# 运行开发服务器
npm run dev
App Router
Next.js 13引入了App Router,基于React Server Components,提供了更好的性能和开发体验。
路由示例
app/
├── layout.tsx # 根布局(所有页面共用)
├── page.tsx # / - 首页
├── about/
│ └── page.tsx # /about - 关于页面
└── blog/
└── [slug]/
└── page.tsx # /blog/[slug] - 动态路由
Layout组件
Layout组件定义页面的共享UI:
import type { Metadata } from 'next'
import './globals.css'
export const metadata: Metadata = {
title: 'My App',
description: 'My App Description'
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="zh">
<body>{children}</body>
</html>
)
}
Page组件
Page组件定义具体页面的内容:
export default function Home() {
return (
<div>
<h1>欢迎来到我的网站</h1>
<p>这是首页内容</p>
</div>
)
}
Server Components
Server Components在服务器端渲染,可以减少JavaScript bundle大小,提升性能。
数据获取
Server Components可以直接获取数据:
async function getUser() {
const res = await fetch('https://api.example.com/user')
return res.json()
}
export default async function Profile() {
const user = await getUser()
return <div>Hello, {user.name}!</div>
}
💡 Server Components vs Client Components
默认情况下所有组件都是Server Components。需要使用React hooks、事件处理器等特性的组件需要标记为客户端组件。
客户端组件
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
点击次数: {count}
</button>
)
}
数据获取
Next.js 15提供了多种数据获取策略。
静态生成(Static Generation)
在构建时预渲染页面:
export default async function BlogList() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return (
<div>
{posts.map(post => (
<article key={post.id}>{post.title}</article>
))}
</div>
)
}
// 或者在页面级别配置
export const dynamic = 'force-static'
服务端渲染(Server-Side Rendering)
每次请求时在服务端渲染:
export default async function DynamicData() {
const data = await fetch('https://api.example.com/data', {
cache: 'no-store' // 禁用缓存
})
return <div>{data.message}</div>
}
// 或者在页面级别配置
export const dynamic = 'force-dynamic'
增量静态生成(ISR)
在构建后定期重新生成页面:
export default async function ISRPage() {
const data = await fetch('https://api.example.com/data').then(r => r.json())
return <div>{data.content}</div>
}
export const revalidate = 3600 // 1小时后重新生成
并行数据获取
同时获取多个数据源:
export default async function Dashboard() {
const [users, posts] = await Promise.all([
fetch('https://api.example.com/users').then(r => r.json()),
fetch('https://api.example.com/posts').then(r => r.json())
])
return (
<div>
<Users users={users} />
<Posts posts={posts} />
</div>
)
}
路由系统
Next.js 15的路由系统功能强大且灵活。
动态路由
// app/blog/[slug]/page.tsx
export default async function BlogPost({
params
}: {
params: { slug: string }
}) {
const res = await fetch(`https://api.example.com/posts/${params.slug}`)
const post = await res.json()
return <article>{post.content}</article>
}
路由跳转
import Link from 'next/link'
export default function Navigation() {
return (
<nav>
<Link href="/">首页</Link>
<Link href="/about">关于</Link>
<Link href="/blog">博客</Link>
</nav>
)
}
编程式导航
'use client'
import { useRouter } from 'next/navigation'
export function NavigateButton() {
const router = useRouter()
return (
<button onClick={() => router.push('/about')}>
前往关于页面
</button>
)
}
API Routes
Next.js 15允许你在同一个项目中创建API端点。
创建API Route
// app/api/hello/route.ts
export async function GET() {
return NextResponse.json({ message: 'Hello from Next.js!' })
}
动态API Route
// app/api/users/[id]/route.ts
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const user = await getUserById(params.id)
return NextResponse.json(user)
}
错误处理
export async function GET() {
try {
const data = await fetchData()
return NextResponse.json(data)
} catch (error) {
return NextResponse.json(
{ error: '获取数据失败' },
{ status: 500 }
)
}
}
样式方案
Next.js 15支持多种样式方案。
CSS Modules
// styles/Home.module.css
.container {
padding: 2rem;
}
// app/page.tsx
import styles from './page.module.css'
export default function Page() {
return (
<div className={styles.container}>
首页内容
</div>
)
}
Tailwind CSS
<div className="bg-white rounded-lg shadow-md p-6">
<h2 className="text-2xl font-bold mb-4">标题</h2>
<p className="text-gray-600">内容</p>
</div>
Styled JSX
export default function Component() {
return (
<>
<div>内容</div>
<style jsx>{
`
div {
color: red;
}
`
}</style>
</>
)
}
部署上线
Next.js 15支持多种部署方式。
Vercel部署
Vercel是Next.js的官方平台:
# 安装Vercel CLI
npm install -g vercel
# 部署项目
vercel
Docker部署
# Dockerfile
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]
⚠️ 部署注意事项
部署前确保配置了正确的环境变量,特别是数据库连接、API密钥等敏感信息。生产环境建议使用环境变量管理配置。
结语
Next.js 15为React开发带来了革命性的改进,特别是App Router和Server Components让全栈开发变得更加简单高效。
通过本教程,你应该已经掌握了Next.js 15的核心概念和基本用法。接下来建议你:
- 动手实践,创建一个完整的项目
- 深入学习高级特性,如中间件、国际化等
- 关注官方文档和更新,及时了解新特性
- 参与社区,与其他开发者交流经验
Next.js的生态正在快速发展,掌握它将为你的前端开发生涯开启新的篇章!