Next.js 教程
项目概述
Next.js 是一款基于 React 的全栈框架,用于构建现代化的 Web 应用。它由 Vercel 公司开发并维护,提供了服务端渲染、静态网站生成、API 路由等功能,帮助开发者构建高性能、SEO 友好的 Web 应用。Next.js 简化了 React 应用的构建过程,提供了良好的开发体验和优化的生产构建。
主要特点
- **服务端渲染 (SSR)**:提高首屏加载速度和 SEO 友好性
- **静态网站生成 (SSG)**:预渲染页面,提供极致的加载性能
- **增量静态再生 (ISR)**:结合 SSR 和 SSG 的优点,支持动态内容的静态生成
- API 路由:在同一项目中构建 API 端点
- 中间件:在请求处理过程中执行代码
- 自动代码分割:优化加载性能
- 文件系统路由:基于文件系统的路由系统,简化路由配置
- TypeScript 支持:内置 TypeScript 支持
- 优化的构建系统:自动优化生产构建
适用场景
- 构建 SEO 友好的网站
- 开发需要服务端渲染的应用
- 构建静态网站
- 全栈应用开发
- 需要高性能的 Web 应用
安装与设置
方法一:使用 create-next-app
# 创建新的 Next.js 项目
npx create-next-app@latest my-app
# 进入项目目录
cd my-app
# 启动开发服务器
npm run dev方法二:手动设置
# 创建项目目录
mkdir my-app
cd my-app
# 初始化 npm 项目
npm init -y
# 安装依赖
npm install next react react-dom
# 在 package.json 中添加脚本在 package.json 中添加以下脚本:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next export"
}
}项目结构
Next.js 项目的基本结构如下:
my-app/
├── app/ # App Router(Next.js 13+)
├── pages/ # Pages Router
│ ├── api/ # API 路由
│ └── index.js # 首页
├── public/ # 静态资源
├── styles/ # 样式文件
├── components/ # 组件
├── lib/ # 工具函数
├── next.config.js # Next.js 配置
└── package.json # 项目配置核心概念
1. 路由系统
Next.js 提供了两种路由系统:Pages Router 和 App Router。
Pages Router
基于文件系统的路由,文件存放在 pages 目录中:
// pages/index.js - 首页
import React from 'react';
export default function Home() {
return (
<div>
<h1>Welcome to Next.js!</h1>
<p>This is the homepage.</p>
</div>
);
}
// pages/about.js - 关于页
import React from 'react';
export default function About() {
return (
<div>
<h1>About Page</h1>
<p>This is the about page.</p>
</div>
);
}
// pages/blog/[id].js - 动态路由
import React from 'react';
import { useRouter } from 'next/router';
export default function BlogPost() {
const router = useRouter();
const { id } = router.query;
return (
<div>
<h1>Blog Post {id}</h1>
<p>This is the blog post with id {id}.</p>
</div>
);
}App Router
Next.js 13+ 引入的新路由系统,基于 React Server Components:
// app/page.js - 首页
import React from 'react';
export default function Home() {
return (
<div>
<h1>Welcome to Next.js!</h1>
<p>This is the homepage.</p>
</div>
);
}
// app/about/page.js - 关于页
import React from 'react';
export default function About() {
return (
<div>
<h1>About Page</h1>
<p>This is the about page.</p>
</div>
);
}
// app/blog/[id]/page.js - 动态路由
import React from 'react';
export default function BlogPost({ params }) {
const { id } = params;
return (
<div>
<h1>Blog Post {id}</h1>
<p>This is the blog post with id {id}.</p>
</div>
);
}2. 数据获取
Next.js 提供了多种数据获取方法,适用于不同的渲染策略。
Pages Router 中的数据获取
- getStaticProps:在构建时获取数据,用于静态生成页面
- getServerSideProps:在每个请求时获取数据,用于服务端渲染页面
- getStaticPaths:为动态路由生成静态路径
// pages/blog/[id].js
import React from 'react';
export default function BlogPost({ post }) {
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}
// 为动态路由生成静态路径
export async function getStaticPaths() {
// 获取所有博客文章 ID
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
// 生成路径
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}));
return {
paths,
fallback: false, // 404 for paths not generated
};
}
// 在构建时获取数据
export async function getStaticProps({ params }) {
// 获取单个博客文章
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return {
props: { post },
revalidate: 60, // 60秒后重新生成
};
}App Router 中的数据获取
使用 React Server Components 和 fetch API:
// app/blog/[id]/page.js
import React from 'react';
async function getPost(id) {
const res = await fetch(`https://api.example.com/posts/${id}`, {
next: { revalidate: 60 }, // 60秒后重新验证
});
if (!res.ok) {
throw new Error('Failed to fetch post');
}
return res.json();
}
export default async function BlogPost({ params }) {
const post = await getPost(params.id);
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}3. API 路由
Next.js 允许在 pages/api 目录中创建 API 端点:
// pages/api/hello.js
import React from 'react';
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' });
}
// pages/api/users/[id].js
export default function handler(req, res) {
const { id } = req.query;
res.status(200).json({ id, name: `User ${id}` });
}在 App Router 中,API 路由位于 app/api 目录:
// app/api/hello/route.js
export async function GET(request) {
return Response.json({ name: 'John Doe' });
}
export async function POST(request) {
const data = await request.json();
return Response.json({ ...data, id: 1 });
}4. 中间件
Next.js 中间件允许在请求处理过程中执行代码:
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(request) {
// 检查是否有认证令牌
const token = request.cookies.get('token')?.value;
// 如果没有令牌,重定向到登录页
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*'],
};5. 静态资源
静态资源存放在 public 目录中,可以通过根路径访问:
// 访问 public/images/logo.png
<img src="/images/logo.png" alt="Logo" />常用功能
1. 导航
使用 next/link 组件进行客户端导航:
import Link from 'next/link';
export default function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog/1">Blog Post 1</Link>
</nav>
);
}2. 图片优化
使用 next/image 组件优化图片:
import Image from 'next/image';
export default function ImageExample() {
return (
<div>
<Image
src="/images/photo.jpg"
width={500}
height={300}
alt="Photo"
priority
/>
</div>
);
}3. 字体优化
使用 next/font 优化字体:
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function FontExample() {
return (
<div className={inter.className}>
<h1>Hello with Inter font</h1>
<p>This text uses the Inter font.</p>
</div>
);
}4. 布局
在 App Router 中使用布局组件:
// app/layout.js
import React from 'react';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<header>
<h1>My Website</h1>
</header>
<main>{children}</main>
<footer>
<p>© 2024 My Website</p>
</footer>
</body>
</html>
);
}5. 错误处理
在 App Router 中使用错误边界:
// app/error.js
'use client';
export default function Error({ error, reset }) {
return (
<div>
<h1>Something went wrong!</h1>
<p>{error.message}</p>
<button onClick={() => reset()}>Try again</button>
</div>
);
}高级功能
1. 国际化
Next.js 支持国际化路由:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
i18n: {
locales: ['en', 'zh'],
defaultLocale: 'en',
},
};
module.exports = nextConfig;创建国际化页面:
pages/
├── index.js # 默认语言 (en)
├── about.js # 默认语言 (en)
├── zh/
│ ├── index.js # 中文
│ └── about.js # 中文2. 认证
实现基于 JWT 的认证系统:
// pages/api/auth/login.js
export default async function handler(req, res) {
const { email, password } = req.body;
// 验证用户
if (email === 'user@example.com' && password === 'password') {
// 生成令牌
const token = 'your-jwt-token';
// 设置cookie
res.setHeader('Set-Cookie', `token=${token}; HttpOnly; Path=/; Max-Age=86400`);
res.status(200).json({ success: true });
} else {
res.status(401).json({ success: false, message: 'Invalid credentials' });
}
}
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(request) {
const token = request.cookies.get('token')?.value;
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}3. 数据库集成
集成 PostgreSQL 数据库:
npm install pg// lib/db.js
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
export default async function query(text, params) {
const client = await pool.connect();
try {
const res = await client.query(text, params);
return res;
} finally {
client.release();
}
}
// pages/api/users.js
import query from '../../lib/db';
export default async function handler(req, res) {
try {
const result = await query('SELECT * FROM users');
res.status(200).json(result.rows);
} catch (error) {
res.status(500).json({ error: error.message });
}
}4. 部署
部署到 Vercel
- 推送代码到 GitHub 仓库
- 在 Vercel 上导入仓库
- 配置构建选项
- 部署应用
部署到其他平台
# 构建应用
npm run build
# 导出静态网站(可选)
npm run export性能优化
1. 代码分割
Next.js 自动进行代码分割,也可以手动分割代码:
import dynamic from 'next/dynamic';
// 懒加载组件
const HeavyComponent = dynamic(() => import('../components/HeavyComponent'), {
loading: () => <p>Loading...</p>,
});
export default function Page() {
return (
<div>
<HeavyComponent />
</div>
);
}2. 图片优化
使用 next/image 组件:
import Image from 'next/image';
export default function ProductPage() {
return (
<div>
<Image
src="/products/1.jpg"
width={800}
height={600}
alt="Product"
priority
/>
</div>
);
}3. 缓存策略
使用 revalidate 选项缓存数据:
// 静态生成页面,每60秒重新验证
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: { data },
revalidate: 60, // 60秒
};
}
// App Router 中
async function getData() {
const res = await fetch('https://api.example.com/data', {
next: { revalidate: 60 },
});
return res.json();
}4. 字体优化
使用 next/font:
import { Inter, Roboto } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
const roboto = Roboto({ subsets: ['latin'], weight: ['400', '700'] });
export default function Page() {
return (
<div className={inter.className}>
<h1 style={{ fontFamily: roboto.style.fontFamily }}>Hello</h1>
<p>This text uses Inter font</p>
</div>
);
}最佳实践
1. 项目结构
- 按功能模块组织代码
- 使用文件夹结构管理组件
- 分离关注点(UI、逻辑、数据)
- 为组件添加清晰的文档和注释
2. 数据获取
- 根据页面类型选择合适的数据获取方法
- 使用
revalidate选项缓存数据 - 避免在客户端获取敏感数据
- 优化 API 请求,减少网络延迟
3. 性能
- 使用
next/image优化图片 - 使用
next/font优化字体 - 合理使用代码分割
- 优化首屏加载速度
4. 安全性
- 使用环境变量存储敏感信息
- 实现适当的认证和授权
- 验证用户输入
- 防止 CSRF 和 XSS 攻击
5. 测试
- 为组件编写单元测试
- 测试 API 路由
- 测试中间件逻辑
- 进行端到端测试
常见问题与解决方案
1. 路由问题
问题:路由不工作或参数获取不到。
解决方案:
- 检查文件路径是否正确
- 确保动态路由文件名正确(如
[id].js) - 在 App Router 中,使用
params属性获取路由参数 - 在 Pages Router 中,使用
useRouter钩子获取路由参数
2. 数据获取问题
问题:数据获取失败或不更新。
解决方案:
- 检查 API 端点是否可达
- 验证数据获取方法是否正确
- 检查
revalidate配置 - 确保错误处理正确
3. 部署问题
问题:部署后应用不工作。
解决方案:
- 检查环境变量配置
- 验证构建过程是否成功
- 检查服务器日志
- 确保 API 路由配置正确
4. 性能问题
问题:应用加载缓慢。
解决方案:
- 使用
next/image优化图片 - 实现代码分割
- 优化数据获取
- 使用静态生成或增量静态再生
5. 样式问题
问题:样式不应用或不一致。
解决方案:
- 检查样式导入是否正确
- 确保 CSS 模块命名正确
- 验证 Tailwind CSS 配置(如果使用)
- 检查样式优先级
参考资源
总结
Next.js 是一款功能强大的 React 全栈框架,提供了服务端渲染、静态网站生成、API 路由等功能,帮助开发者构建高性能、SEO 友好的 Web 应用。通过本教程的学习,你应该已经掌握了 Next.js 的核心概念、使用方法和最佳实践。
Next.js 的设计理念是"约定优于配置",通过合理的默认配置和文件系统路由,简化了 React 应用的构建过程。它的自动代码分割、图片优化、字体优化等功能,帮助开发者构建性能优异的应用。
作为 React 生态系统中最流行的框架之一,Next.js 拥有庞大的开发者社区和完善的文档,这使得它成为构建现代化 Web 应用的理想选择。无论是简单的静态网站还是复杂的全栈应用,Next.js 都能满足你的需求。
随着 Next.js 的不断发展,它也在持续改进和更新,添加新的功能和优化性能。建议你持续关注 Next.js 的官方文档和社区动态,以便及时了解最新的功能和最佳实践。