Next.js 已经成为 React 生态系统中最受欢迎的框架之一,它简化了 React 应用的开发流程,提供了开箱即用的解决方案。
什么是 Next.js?
Next.js 是一个基于 React 的生产级全栈框架,由 Vercel 公司开发维护。它提供了许多强大功能:
- 服务端渲染(SSR) - 更好的 SEO 和初始加载性能
- 静态站点生成(SSG) - 超快的页面加载速度
- API 路由 - 轻松创建后端 API
- 自动代码分割 - 优化打包大小
- 零配置 - 开箱即用的优化配置
- TypeScript 支持 - 完整的类型支持
- 快速刷新 - 极佳的开发体验
环境准备
在开始之前,确保你的系统已安装:
- Node.js 16.8 或更高版本
- npm、yarn 或 pnpm 包管理器
创建第一个 Next.js 项目
方法一:使用 create-next-app(推荐)
bash
npx create-next-app@latest my-nextjs-app
cd my-nextjs-app
npm run dev
创建过程中,CLI 会询问一些配置选项:
- 是否使用 TypeScript?(推荐选择是)
- 是否使用 ESLint?(推荐选择是)
- 是否使用 Tailwind CSS?(根据喜好选择)
- 是否使用
src/
目录?(可选) - 是否使用 App Router?(新项目推荐选择是)
- 是否自定义导入别名?(通常选择否)
方法二:手动设置
如果你喜欢从零开始配置:
bash
mkdir my-nextjs-app
cd my-nextjs-app
npm init -y
npm install next react react-dom
在 package.json
中添加脚本:
json
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
}
创建必要的目录结构:
bash
mkdir app pages public
Next.js 版本对比与演进
Next.js 主要版本特性对比
特性维度 | v12 (Pages Router) | v13 (过渡版) | v14+ (App Router稳定版) | 说明 |
---|---|---|---|---|
路由系统 | pages/目录 文件即路由 | pages/和 app/共存 | app/目录 全面转向 App Router | 最大的架构变革 |
数据获取 | getStaticProps getServerSideProps | 支持 async组件 (试验性) | 直接 async组件 服务端获取数据 | 更直观,代码更少 |
组件类型 | 全是客户端组件 | 引入 服务端组件 (需配置) | 服务端组件为默认 客户端需 'use client' | 混合渲染,性能优化 |
布局系统 | 手动包装布局 (如 ) | 支持 layout.js (试验性) | 文件级布局 layout.js自动嵌套 | 布局共享更简单 |
API 路由 | pages/api/目录 | pages/api/ 和 app/api/共存 | app/api/route.js 基于 HTTP 方法 (GET, POST) | 更符合 REST 规范 |
元数据管理 | 手动在 中写 | 部分支持 metadata | 完整 的 metadataAPI 支持 SEO和社交卡片 | 静态SEO优化更方便 |
渲染模式 | SSG, SSR, CSR | 支持流式渲染 (Streaming) + Suspense | 流式渲染稳定 部分 HTML 先输出 | 提升首屏加载速度 |
Pages Router vs App Router 详细对比
Pages Router(传统方式)
项目结构:
pages/
├── index.js # / 路由
├── about.js # /about 路由
├── blog/
│ ├── index.js # /blog 路由
│ └── [id].js # /blog/1 动态路由
└── api/
└── users.js # /api/users API 路由
特点:
- 基于文件系统的路由
- 使用
getServerSideProps
、getStaticProps
进行数据获取 - 相对成熟稳定,社区资源丰富
示例代码:
jsx
// pages/index.js
export default function Home({ posts }) {
return (
<div>
<h1>首页</h1>
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/posts')
const posts = await res.json()
return {
props: { posts }
}
}
App Router(新方式,Next.js 13+)
项目结构:
app/
├── layout.js # 根布局
├── page.js # / 路由
├── about/
│ └── page.js # /about 路由
├── blog/
│ ├── page.js # /blog 路由
│ └── [id]/
│ └── page.js # /blog/1 动态路由
└── api/
└── users/
└── route.js # /api/users API 路由
特点:
- 基于 React Server Components
- 使用 async/await 进行服务端数据获取
- 支持嵌套布局和加载状态
- 更好的性能优化
示例代码:
jsx
// app/page.js
async function getPosts() {
const res = await fetch('https://api.example.com/posts')
return res.json()
}
export default async function Home() {
const posts = await getPosts()
return (
<div>
<h1>首页</h1>
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
为什么推荐使用 App Router?
- 更好的性能:默认使用 React Server Components
- 更简单的数据获取:直接使用 async/await
- 改进的布局系统:嵌套布局支持
- 更好的加载状态:内置 loading.js 文件
- 未来导向:React 团队推荐的方向
Next.js 如何优化 SEO
1. 服务端渲染(SSR)
传统 React SPA 的问题:
html
<!-- 初始 HTML -->
<div id="root"></div>
<!-- 需要 JavaScript 执行后才能看到内容 -->
Next.js SSR 的优势:
html
<!-- 服务端直接返回完整 HTML -->
<div>
<h1>我的博客</h1>
<article>完整的文章内容...</article>
</div>
搜索引擎优化效果:
- 爬虫可以直接看到完整内容
- 不需要等待 JavaScript 执行
- 更好的内容索引
2. 静态站点生成(SSG)
构建时生成静态 HTML:
jsx
// pages/posts/[id].js (Pages Router)
export async function getStaticPaths() {
// 构建时获取所有可能的路径
const posts = await getPosts()
const paths = posts.map(post => ({
params: { id: post.id.toString() }
}))
return { paths, fallback: false }
}
export async function getStaticProps({ params }) {
// 构建时生成静态页面
const post = await getPost(params.id)
return { props: { post } }
}
SEO 优势:
- 极快的加载速度(直接返回 HTML)
- 更好的 Core Web Vitals 分数
- 搜索引擎更喜欢快速加载的页面
3. 元数据优化
Pages Router 方式:
jsx
// pages/index.js
import Head from 'next/head'
export default function Home() {
return (
<>
<Head>
<title>我的网站 - 最佳 React 框架</title>
<meta name="description" content="Next.js 是React的最佳框架..." />
<meta name="keywords" content="nextjs, react, ssr, seo" />
</Head>
<main>内容</main>
</>
)
}
App Router 方式(更简洁):
jsx
// app/page.js
export const metadata = {
title: '我的网站 - 最佳 React 框架',
description: 'Next.js 是React的最佳框架...',
keywords: 'nextjs, react, ssr, seo',
}
export default function Home() {
return <main>内容</main>
}
4. 语义化 URL 和路由
动态路由优化:
jsx
// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [post.image],
},
}
}
5. 图片优化和懒加载
jsx
import Image from 'next/image'
export default function OptimizedImage() {
return (
<Image
src="/hero.jpg"
alt="描述性文字,有利于SEO"
width={800}
height={400}
priority={true} // 关键图片优先加载
placeholder="blur" // 模糊占位符
/>
)
}
项目结构深度解析
App Router 完整项目结构
my-nextjs-app/
├── app/ # App Router 目录
│ ├── globals.css # 全局样式
│ ├── layout.js # 根布局组件
│ ├── page.js # 首页组件
│ ├── loading.js # 加载状态组件
│ ├── error.js # 错误边界组件
│ ├── not-found.js # 404 页面
│ ├── about/
│ │ └── page.js # /about 页面
│ ├── blog/
│ │ ├── page.js # /blog 列表页
│ │ ├── loading.js # 博客页面的加载状态
│ │ └── [slug]/
│ │ └── page.js # /blog/xxx 详情页
│ └── api/
│ └── posts/
│ └── route.js # API 路由
├── components/ # 可复用组件
│ ├── ui/ # UI 基础组件
│ └── layout/ # 布局组件
├── lib/ # 工具函数库
├── public/ # 静态资源
└── next.config.js # Next.js 配置
数据获取深度解析
服务端数据获取模式
1. 静态生成(推荐用于内容型网站)
jsx
// 构建时生成,适合不经常变化的内容
async function getStaticData() {
const res = await fetch('https://api.example.com/posts')
return res.json()
}
2. 服务端渲染(推荐用于动态内容)
jsx
// 每次请求时生成,适合实时数据
async function getServerData() {
const res = await fetch('https://api.example.com/posts', {
cache: 'no-store' // 禁止缓存
})
return res.json()
}
3. 增量静态再生(ISR)
jsx
// 静态生成,但定期更新
async function getISRData() {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 60 } // 60秒后重新验证
})
return res.json()
}
客户端数据获取最佳实践
jsx
'use client'
import { useState, useEffect } from 'react'
import { useSWR } from 'swr'
export default function ClientComponent() {
const { data, error, isLoading } = useSWR(
'/api/posts',
fetcher,
{
revalidateOnFocus: false,
dedupingInterval: 60000
}
)
if (error) return <div>加载失败</div>
if (isLoading) return <div>加载中...</div>
return (
<div>
{data.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
高级特性与优化
1. 中间件(Middleware)
jsx
// middleware.js
import { NextResponse } from 'next/server'
export function middleware(request) {
// 身份验证检查
if (!request.cookies.get('token')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: '/admin/:path*'
}
2. 国际化(i18n)
javascript
// next.config.js
module.exports = {
i18n: {
locales: ['zh-CN', 'en-US'],
defaultLocale: 'zh-CN',
},
}
3. 环境变量配置
javascript
// .env.local
DATABASE_URL=your_database_url
NEXT_PUBLIC_API_URL=https://api.example.com
// next.config.js
module.exports = {
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
},
}
部署与生产优化
构建优化配置
javascript
// next.config.js
module.exports = {
experimental: {
optimizeCss: true,
},
compiler: {
removeConsole: process.env.NODE_ENV === 'production',
},
images: {
domains: ['example.com'],
formats: ['image/webp', 'image/avif'],
},
}
性能监控
javascript
// app/layout.js
import { Analytics } from '@vercel/analytics/react'
export default function RootLayout({ children }) {
return (
<html lang="zh">
<body>
{children}
<Analytics />
</body>
</html>
)
}
常见问题解决方案
1. 白屏问题
- 检查组件是否正确导出为默认导出
- 确认文件路径和命名符合 Next.js 规范
- 查看浏览器控制台错误信息
2. 样式不生效
- 确认 CSS 文件正确导入
- 检查类名拼写和样式优先级
- 使用开发者工具检查样式应用
3. 构建失败
- 检查 Node.js 版本是否符合要求
- 确认所有依赖正确安装
- 查看构建日志中的具体错误信息