NextJs 基础
概述
Next.js 是一个基于 React 的全栈框架,提供了服务端渲染、静态站点生成、文件路由等能力。
核心特性
- 混合渲染 — 支持 CSR、SSR、SSG、ISR 四种渲染方式
- 文件路由 — 基于文件系统的路由机制
- 全栈能力 — 内置 API Routes,前后端一体开发
- 自动优化 — 图片、字体、脚本自动优化
- Server Actions — 无需手动创建接口,直接调用服务端函数
创建项目
bash
# 默认 App Router(推荐)
npx create-next-app@latest my-app
# Pages Router
npx create-next-app@latest my-app --use-pages-router# 默认 App Router(推荐)
npx create-next-app@latest my-app
# Pages Router
npx create-next-app@latest my-app --use-pages-router创建过程中可选择 TypeScript、ESLint、Tailwind CSS、src/ 目录等选项。
目录结构
my-app/
src/
app/ # App Router 目录
layout.tsx # 根布局(必须存在)
page.tsx # 首页
globals.css # 全局样式
api/ # API Routes(可选)
public/ # 静态资源
next.config.mjs # Next.js 配置
package.json
tsconfig.jsonmy-app/
src/
app/ # App Router 目录
layout.tsx # 根布局(必须存在)
page.tsx # 首页
globals.css # 全局样式
api/ # API Routes(可选)
public/ # 静态资源
next.config.mjs # Next.js 配置
package.json
tsconfig.jsonApp Router vs Pages Router
| 特性 | App Router | Pages Router |
|---|---|---|
| 引入版本 | Next.js 13.4+ | 初始版本 |
| 路由方式 | 文件路由(page.tsx) | 文件路由(index.tsx) |
| 布局 | layout.tsx 嵌套布局 | 无原生布局支持 |
| 数据获取 | 服务端组件直接 async/await | getServerSideProps / getStaticProps |
| 服务端组件 | 默认支持 | 不支持 |
| API Routes | route.ts | api 目录下文件 |
配置 next.config.mjs
js
/** @type {import('next').NextConfig} */
const nextConfig = {
logging: {
fetches: {
fullUrl: true // 打印 fetch 缓存信息
}
},
images: {
domains: ['example.com'], // 允许的外部图片域名
}
}
export default nextConfig/** @type {import('next').NextConfig} */
const nextConfig = {
logging: {
fetches: {
fullUrl: true // 打印 fetch 缓存信息
}
},
images: {
domains: ['example.com'], // 允许的外部图片域名
}
}
export default nextConfigMetadata 与 SEO
tsx
// 静态 metadata
export const metadata = {
title: 'My App',
description: 'My App Description',
}
// 动态 metadata
export async function generateMetadata({ params }) {
const post = await getPost(params.id)
return {
title: post.title,
description: post.excerpt,
}
}// 静态 metadata
export const metadata = {
title: 'My App',
description: 'My App Description',
}
// 动态 metadata
export async function generateMetadata({ params }) {
const post = await getPost(params.id)
return {
title: post.title,
description: post.excerpt,
}
}App Router 核心约定文件
| 文件名 | 作用 |
|---|---|
page.tsx | 页面组件 |
layout.tsx | 布局(跨路由保持状态) |
template.tsx | 模板(切换路由重新渲染) |
loading.tsx | 加载状态(基于 Suspense) |
error.tsx | 错误边界 |
not-found.tsx | 404 页面 |
route.ts | API 路由处理程序 |
'use client' 指令
'use client' 声明该模块在客户端执行。默认情况下 Next.js 组件是服务端组件:
tsx
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}'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 内置对环境变量的支持:
bash
# .env.local(本地环境,优先级最高)
DATABASE_URL=mysql://localhost:3306/db
NEXT_PUBLIC_API_URL=https://api.example.com # NEXT_PUBLIC_ 前缀暴露给客户端# .env.local(本地环境,优先级最高)
DATABASE_URL=mysql://localhost:3306/db
NEXT_PUBLIC_API_URL=https://api.example.com # NEXT_PUBLIC_ 前缀暴露给客户端| 文件 | 作用 |
|---|---|
.env.local | 本地环境,会覆盖其他配置 |
.env.development | 开发环境(next dev) |
.env.production | 生产环境(next start) |
.env | 所有环境默认值 |
注意:不带 NEXT_PUBLIC_ 前缀的变量仅在服务端可用,客户端代码中访问会返回 undefined。
next/image 图片优化
Next.js 提供内置的 Image 组件,自动优化图片:
tsx
import Image from 'next/image'
// 本地图片
import avatar from './avatar.png'
<Image src={avatar} alt="avatar" />
// 远程图片(需在 next.config.mjs 配置域名)
<Image
src="https://example.com/photo.jpg"
alt="photo"
width={800}
height={600}
priority // 首屏图片优先加载
/>import Image from 'next/image'
// 本地图片
import avatar from './avatar.png'
<Image src={avatar} alt="avatar" />
// 远程图片(需在 next.config.mjs 配置域名)
<Image
src="https://example.com/photo.jpg"
alt="photo"
width={800}
height={600}
priority // 首屏图片优先加载
/>配置远程图片域名
js
// next.config.mjs
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}// next.config.mjs
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}图片特性
- 自动优化 — 转换格式(WebP/AVIF),调整尺寸
- 懒加载 — 默认懒加载,进入视口才加载
- 防止 CLS — 需指定宽高或使用
fill属性 - 占位符 —
placeholder="blur"支持模糊占位
next/font 字体优化
自动优化字体,消除外部请求:
tsx
import { Inter, Geist } from 'next/font/google'
// 自定义 CSS 变量
const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
})
const inter = Inter({ subsets: ['latin'] })
export default function RootLayout({ children }) {
return (
<html lang="en" className={`${geistSans.variable}`}>
<body className={inter.className}>{children}</body>
</html>
)
}import { Inter, Geist } from 'next/font/google'
// 自定义 CSS 变量
const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
})
const inter = Inter({ subsets: ['latin'] })
export default function RootLayout({ children }) {
return (
<html lang="en" className={`${geistSans.variable}`}>
<body className={inter.className}>{children}</body>
</html>
)
}优势:字体文件在构建时下载,与静态资源一起托管,无外部网络请求。
next/script 脚本加载
tsx
import Script from 'next/script'
export default function Page() {
return (
<>
<Script
src="https://analytics.example.com/script.js"
strategy="afterInteractive" // 默认,页面可交互后加载
// strategy="beforeInteractive" // 在页面可交互前加载
// strategy="lazyOnload" // 浏览器空闲时加载
/>
</>
)
}import Script from 'next/script'
export default function Page() {
return (
<>
<Script
src="https://analytics.example.com/script.js"
strategy="afterInteractive" // 默认,页面可交互后加载
// strategy="beforeInteractive" // 在页面可交互前加载
// strategy="lazyOnload" // 浏览器空闲时加载
/>
</>
)
}| strategy | 说明 |
|---|---|
beforeInteractive | 页面可交互前加载(关键脚本) |
afterInteractive | 页面可交互后加载(默认,分析工具) |
lazyOnload | 浏览器空闲时加载(低优先级) |
常用命令
bash
npm run dev # 开发模式
npm run build # 构建
npm start # 启动生产服务
npm run lint # 代码检查npm run dev # 开发模式
npm run build # 构建
npm start # 启动生产服务
npm run lint # 代码检查
Cao Note