迈向现代前端新纪元:Next.js 入门——核心概念深入解析
在当今快速迭代的 Web 开发领域,构建高性能、用户体验优秀且易于维护的现代 Web 应用是每个开发者追求的目标。React 作为构建用户界面的强大库,极大地提高了开发效率。然而,纯粹的客户端渲染(Client-Side Rendering, CSR)模式在某些场景下(如搜索引擎优化 SEO、首屏加载速度、代码分割等)存在局限性。
这时,Next.js 应运而生。它是一个基于 React 的、生产级别的全栈 Web 应用框架,由 Vercel 公司开发和维护。Next.js 在 React 的基础上,提供了诸多开箱即用的功能和优化,极大地简化了构建现代 Web 应用的复杂性,让开发者能够更专注于业务逻辑而非繁琐的配置。
如果你已经有 React 的基础,并希望构建更强大、更优化的 Web 应用,那么学习 Next.js 将是你的下一个重要里程碑。本文将带你深入探索 Next.js 的核心概念,为你打开现代全栈 React 开发的大门。
为什么选择 Next.js?它解决了什么问题?
在深入 Next.js 的具体功能之前,我们先来理解一下为什么 Next.js 如此受欢迎,以及它主要解决了 React 客户端应用开发中的哪些痛点。
传统的客户端渲染(CSR)模式,例如使用 Create React App (CRA) 构建的应用,通常工作流程是:
1. 浏览器请求页面。
2. 服务器返回一个包含少量 HTML 和 <script>
标签的空壳文件。
3. 浏览器下载 JavaScript 文件。
4. 浏览器执行 JavaScript,React 应用开始运行,动态渲染页面内容。
这种模式对于单页应用(SPA)来说,提供了流畅的用户体验,但在以下方面存在挑战:
- 搜索引擎优化 (SEO): 搜索引擎爬虫在抓取页面时,可能无法完整执行 JavaScript 并获取动态加载的内容,导致页面的真实内容无法被索引,影响 SEO。
- 首屏加载速度: 用户需要等待 JavaScript 下载和执行完成后才能看到完整的页面内容,这会导致白屏时间较长,影响用户体验,尤其是在网络条件不佳的情况下。
- 性能优化: 复杂的代码分割、资源预加载等需要手动配置或依赖额外的库,增加了开发和维护的复杂度。
- 服务器端渲染 (SSR) 配置: 如果需要实现服务器端渲染来解决 SEO 和首屏加载问题,传统的 React 应用需要进行复杂的配置,包括服务器设置、路由同步、数据同构等,门槛较高。
- 全栈能力: React 本身只是一个 UI 库,如果需要构建后端 API,通常需要单独的技术栈(如 Node.js + Express, Python + Django/Flask 等),增加了项目复杂性。
Next.js 恰恰是为解决这些问题而设计的。它提供了一套集成的解决方案,让你能够轻松构建具备以下特性的应用:
- 内置服务器端渲染 (SSR) 和静态站点生成 (SSG): Next.js 支持多种渲染策略,可以根据页面特性选择最佳方案,从而改善 SEO 和首屏性能。
- 基于文件系统的路由: 无需手动配置路由,只需在特定目录下创建文件即可自动生成路由。
- 自动代码分割: Next.js 会根据页面自动进行代码分割,只加载当前页面所需的代码,提高加载速度。
- API Routes: 允许你在 Next.js 项目中创建 Node.js 后端 API,实现真正的全栈开发。
- 开箱即用的功能: 包括样式支持(CSS Modules, CSS-in-JS, Sass)、图片优化、环境变量、Fast Refresh 等,提升开发效率和体验。
- 简单易用的部署: 与 Vercel 等平台深度集成,部署流程非常简单。
总而言之,Next.js 为 React 开发者提供了一个强大而高效的框架,它抽象了许多复杂的底层配置,让开发者能够更专注于构建优秀的 Web 应用。
入门第一步:创建你的第一个 Next.js 应用
开始 Next.js 之旅最简单的方式就是使用官方提供的 create-next-app
工具,类似于 React 的 CRA。
确保你安装了 Node.js (推荐 LTS 版本) 和 npm 或 yarn 或 pnpm。
打开终端,运行以下命令:
“`bash
npx create-next-app@latest my-next-app
或者使用 yarn
yarn create next-app my-next-app
或者使用 pnpm
pnpm create next-app my-next-app
“`
运行命令后,它会询问你一些配置问题,例如:
- 项目名称 (
my-next-app
) - 是否使用 TypeScript (推荐选择 Yes)
- 是否使用 ESLint (推荐选择 Yes)
- 是否使用 Tailwind CSS (根据喜好选择)
- 是否使用
src
目录 (推荐选择 Yes) - 是否使用 App Router (推荐选择 Yes,这是 Next.js 13+ 的新标准,尽管本文也会介绍 Pages Router 的核心概念,但 App Router 是未来)
- 是否自定义 import alias (e.g.
@/*
) (推荐选择 Yes)
选择完成后,工具会自动创建项目并安装依赖。
进入项目目录:
bash
cd my-next-app
运行开发服务器:
“`bash
npm run dev
或者 yarn dev
或者 pnpm dev
“`
现在,打开浏览器访问 http://localhost:3000
,你就能看到 Next.js 的默认欢迎页面了!
项目结构概览 (App Router 为主,附带 Pages Router 介绍)
create-next-app
创建的项目结构简洁明了。对于 Next.js 13+ 且选择了 App Router 的项目,核心目录通常是 app
和 public
。
my-next-app/
├── app/ # App Router 目录
│ ├── layout.tsx # 根布局文件
│ ├── page.tsx # 根页面文件 (对应 '/')
│ └── globals.css # 全局 CSS
├── public/ # 静态资源目录
│ └── favicon.ico # 网站图标
├── src/ # 如果你选择了 src 目录
│ ├── app/ # App Router 目录 (同上)
│ └── components/ # 存放可复用 React 组件
├── next.config.js # Next.js 配置文件
├── package.json # 项目依赖和脚本
├── README.md # 项目说明
└── tsconfig.json # TypeScript 配置文件 (如果选择了 TypeScript)
核心目录和文件说明:
-
app/
(App Router): 这是 Next.js 13+ 引入的新的路由和渲染范式。它基于文件系统,目录结构直接映射到 URL 路径。page.tsx
: 对应一个路由段的 UI 界面。例如app/page.tsx
对应根路由/
,app/about/page.tsx
对应/about
。layout.tsx
: 对应一个路由段的布局。布局会包裹其下的page
文件,可以用来定义共享的 UI 结构(如导航栏、侧边栏)。app/layout.tsx
是应用的根布局。template.tsx
: 类似于layout
,但每次导航时都会重新创建组件实例,用于一些需要状态重置或入口/出口动画的场景。loading.tsx
: 在加载同一路由段下的内容时显示的 loading UI。error.tsx
: 处理同一路由段及其子段中的错误。not-found.tsx
: 处理同一路由段及其子段下的 404 错误。default.tsx
: 作为 parallel routes 的 fallback。route.ts
: 对应 API 路由(新的 App Router API 路由)。[folderName]
: 定义动态路由参数,例如app/products/[id]/page.tsx
。
-
public/
: 这个目录用于存放静态资源,如图片、字体、Favicon 等。放在这里的资源可以直接通过根路径访问,例如public/favicon.ico
可以通过/favicon.ico
访问。 -
src/
: 如果你选择了这个选项,你的应用代码会放在src/app
、src/components
等目录下,这是一种常见的代码组织方式。 -
next.config.js
: Next.js 的配置文件,你可以在这里配置各种构建选项、环境变量、重定向、图片优化策略等。
Pages Router (传统方式,Next.js 13- 或选择不使用 App Router 时):
如果你没有选择 App Router,或者你的项目是基于 Next.js 12 或更早版本,核心目录是 pages
。
my-next-app/
├── pages/ # Pages Router 目录
│ ├── index.tsx # 对应 '/' 路径
│ ├── about.tsx # 对应 '/about' 路径
│ ├── _app.tsx # 自定义 App 组件 (用于初始化页面,如添加全局样式、Providers)
│ ├── _document.tsx # 自定义 Document 组件 (用于修改 HTML 结构,如添加 meta 标签、引入外部脚本)
│ └── api/ # API Routes 目录
│ └── hello.ts # 对应 '/api/hello' 路径
├── public/ # 静态资源目录 (同上)
├── components/ # 存放可复用 React 组件
├── next.config.js # Next.js 配置文件
├── package.json # 项目依赖和脚本
└── tsconfig.json # TypeScript 配置文件
pages/
(Pages Router): 这个目录下的文件直接映射到 URL 路径。pages/index.tsx
: 对应应用的根路由/
。pages/about.tsx
: 对应/about
路由。pages/posts/[slug].tsx
: 对应动态路由,如/posts/first-post
,/posts/another-post
。[slug]
是动态参数。pages/api/
: 这个目录用于创建 API 路由。pages/api/hello.ts
对应/api/hello
接口。pages/_app.tsx
: 用于自定义应用的初始化,例如在所有页面加载前应用全局 CSS,或者注入 Context Providers。pages/_document.tsx
: 用于自定义应用的 HTML 文档结构(<html>
,<body>
等),例如添加自定义字体、meta 标签等。
注意: App Router 是 Next.js 的最新推荐路由方式,它带来了服务器组件、嵌套路由、并行路由等强大功能,是 Next.js 的发展方向。虽然 Pages Router 仍然可用且被广泛使用,但新项目建议优先考虑 App Router。本文后续内容会结合介绍 App Router 的概念,但也会触及 Pages Router 中对应的概念,以便理解 Next.js 的演进和兼容性。
核心概念一:基于文件系统的路由
无论是 App Router 还是 Pages Router,Next.js 最直观的核心概念之一就是其基于文件系统的路由。你无需安装和配置像 React Router 这样的库,Next.js 会根据 app
或 pages
目录下的文件结构自动生成应用的路由。
App Router 中的路由:
- 约定:
app
目录下的文件夹代表 URL 的一个段,而该文件夹内的page.tsx
文件则定义了该路由段的 UI。 - 示例:
app/page.tsx
->/
app/about/page.tsx
->/about
app/dashboard/settings/page.tsx
->/dashboard/settings
- 嵌套路由和布局: 通过创建嵌套文件夹,可以创建嵌套路由。例如
app/dashboard/page.tsx
和app/dashboard/settings/page.tsx
。你可以在app/dashboard/layout.tsx
中定义一个布局,它将应用于/dashboard
和/dashboard/settings
及其子路由。 - 动态路由: 使用方括号
[]
定义动态路由参数。例如app/products/[id]/page.tsx
会匹配/products/1
,/products/abc
等路径,id
参数可以在页面组件中获取。
Pages Router 中的路由:
- 约定:
pages
目录下的文件直接映射到 URL。文件名为index.js
或index.tsx
对应目录的根路径。 - 示例:
pages/index.tsx
->/
pages/about.tsx
->/about
pages/posts/index.tsx
->/posts
pages/dashboard/settings.tsx
->/dashboard/settings
- 动态路由: 使用方括号
[]
定义动态文件或目录名。例如pages/posts/[slug].tsx
会匹配/posts/hello-world
等路径,slug
参数可以在页面组件中获取。pages/[user]/settings.tsx
会匹配/john/settings
,/jane/settings
等。 - API 路由: 任何放在
pages/api
目录下的文件都会被视为 API 路由,而不是页面。例如pages/api/user.ts
对应/api/user
。
导航:
Next.js 提供了 <Link>
组件 (next/link
) 用于在应用内部进行客户端路由跳转。使用 <Link>
组件可以实现单页应用的平滑导航,而无需触发浏览器刷新。
“`jsx
// App Router 或 Pages Router 中都适用
import Link from ‘next/link’;
function Navigation() {
return (
);
}
“`
相比于传统的 <a>
标签,<Link>
组件会自动进行预加载(Prefetching),即在链接进入用户视口时,Next.js 会在后台预加载目标页面所需的资源,从而在用户点击时实现即时导航。
核心概念二:渲染策略 (SSG, SSR, CSR, ISR)
这是 Next.js 最强大也是最核心的特性之一。Next.js 提供了多种渲染策略,允许你根据页面内容的特性选择最优的方式,以平衡性能、SEO 和数据实时性。
1. 静态站点生成 (Static Site Generation, SSG)
- 工作原理: 在项目构建时 (build time),Next.js 会预先渲染页面,生成静态的 HTML 文件以及相关的 CSS 和 JavaScript。这些静态文件可以直接部署到 CDN 上。
- 优点:
- 极快的访问速度: 用户请求时直接获取预生成的 HTML,无需服务器端实时计算。
- 优秀的 SEO: 搜索引擎爬虫可以直接抓取完整的 HTML 内容。
- 低成本部署: 静态文件托管成本非常低廉。
- 适用场景: 内容不经常变化或变化不要求实时性高的页面,如博客文章、营销落地页、文档网站、产品列表页等。
- App Router 实现 (推荐): 默认情况下,
app
目录下的组件是 React Server Components,它们在服务器上渲染为静态 HTML。数据获取通常在 Server Component 中使用fetch
或其他库完成,并自动缓存。 -
Pages Router 实现: 在页面组件中导出
getStaticProps
函数。这个函数在构建时运行,用于获取页面所需的 props。“`javascript
// pages/posts/[slug].js (Pages Router example)
import { getStaticProps, getStaticPaths } from ‘next’;// 这会在构建时运行,为每个 slug 获取数据
export const getStaticProps = async ({ params }) => {
const postData = await getPostBySlug(params.slug); // 模拟数据获取
return {
props: {
postData,
},
// revalidate: 60, // 启用 ISR,可选
};
};// 这会在构建时运行,定义需要预渲染的动态路径
export const getStaticPaths = async () => {
const paths = await getAllPostSlugs(); // 模拟获取所有 slug
return {
paths, // [{ params: { slug: ‘post-a’ } }, { params: { slug: ‘post-b’ } }]
fallback: ‘blocking’, // 或者 true / false
};
};// 页面组件接收 getStaticProps 返回的 props
function Post({ postData }) {
return ({postData.title}
{postData.content}
);
}export default Post;
``
getStaticProps
*: 负责获取数据。
getStaticPaths
*: 如果是动态路由 (
[slug].js),需要配合
getStaticPaths来告诉 Next.js 在构建时需要生成哪些具体路径的页面(例如
/posts/hello-world,
/posts/another-post)。
fallback选项决定了当用户请求一个构建时未生成的路径时 Next.js 的行为 (
false-> 404;
true-> 客户端渲染并生成新静态文件;
‘blocking’` -> 服务器端渲染并缓存)。
2. 服务器端渲染 (Server-Side Rendering, SSR)
- 工作原理: 在用户每次请求页面时,Next.js 服务器都会实时执行 React 代码,将页面渲染成 HTML,然后将 HTML 发送给浏览器。客户端接收到 HTML 后,JavaScript 会在后台加载并“激活”页面,使其具备交互能力(hydration)。
- 优点:
- 优秀的 SEO: 搜索引擎爬虫可以获取完整的 HTML 内容。
- 较好的首屏加载速度: 用户可以快速看到页面内容,即使内容是动态生成的。
- 数据实时性高: 每次请求都会获取最新数据。
- 适用场景: 内容频繁变化、需要实时数据的页面,或需要根据用户身份显示不同内容的页面,如电商商品详情页、新闻详情页、用户仪表盘等。
- App Router 实现 (推荐): 默认情况下,
app
目录下的 Server Components 也是支持 SSR 的。如果数据是动态的且不应该被缓存(例如依赖 Cookie 或 Header),可以使用fetch
API 并设置cache: 'no-store'
,或者使用 Router Handler (新的 API 路由)。 -
Pages Router 实现: 在页面组件中导出
getServerSideProps
函数。这个函数在每次用户请求页面时都会在服务器端运行。“`javascript
// pages/user/[id].js (Pages Router example)
import { getServerSideProps } from ‘next’;// 这会在每次请求时运行,为当前请求获取数据
export const getServerSideProps = async ({ params, req, res }) => {
const userData = await fetchUserData(params.id, req.headers.cookie); // 模拟数据获取,可访问请求信息
if (!userData) {
return {
notFound: true, // 返回 404 页面
};
}
return {
props: {
userData,
},
};
};// 页面组件接收 getServerSideProps 返回的 props
function UserProfile({ userData }) {
return ({userData.name}
{userData.email}
);
}export default UserProfile;
``
getServerSideProps
*: 负责在每次请求时获取数据。它可以访问请求相关的上下文信息(如
req,
res`)。
3. 客户端渲染 (Client-Side Rendering, CSR)
- 工作原理: 这是传统的 React SPA 模式。服务器返回最小的 HTML 文件,数据获取和页面渲染完全在浏览器端通过 JavaScript 执行。
- 优点:
- 适合强交互应用: 用户体验流畅,页面切换快,适合仪表盘、复杂的表单等。
- 缺点:
- SEO 不友好( unless you use dynamic rendering like Prerender.io or have a robust client-side SEO strategy).
- 首屏加载可能较慢。
- 适用场景: 用户登录后的仪表盘、高度依赖用户交互的内部工具等对 SEO 和首屏不敏感的页面。
- App Router 实现: 在组件文件的顶部添加
'use client'
指令。这会将该组件及其所有子组件标记为 Client Components。数据获取可以在 Client Component 中使用 React 的 Effect Hook (useEffect
) 或 SWR, React Query 等库进行。 -
Pages Router 实现: 这是 Pages Router 页面的默认行为。在页面组件中使用
useEffect
等 React Hook 进行数据获取。“`javascript
// pages/dashboard.js (Pages Router example)
import { useState, useEffect } from ‘react’;function Dashboard() {
const [data, setData] = useState(null);useEffect(() => {
// 在客户端加载后执行数据获取
fetch(‘/api/dashboard-data’)
.then(res => res.json())
.then(setData);
}, []); // 仅在组件挂载时执行一次if (!data) {
returnLoading dashboard…
;
}return (
Dashboard
Data: {JSON.stringify(data)}
);
}export default Dashboard;
“`
4. 增量静态再生 (Incremental Static Regeneration, ISR)
- 工作原理: 这是 SSG 的一个增强。你可以在
getStaticProps
中指定一个revalidate
参数(秒数)。Next.js 会在构建时生成页面的静态版本。当用户请求页面时,如果距离上次生成超过revalidate
秒,Next.js 会返回旧的(缓存的)静态页面,同时在后台重新生成新的静态页面来替换旧的缓存。随后的请求就会获取到新的页面。 - 优点: 结合了 SSG 的性能优势和 SSR 的数据更新能力,无需完全重建整个站点即可更新静态内容。
- 适用场景: 内容更新频率较高但不需要极致实时的页面,如电商网站首页推荐商品、博客文章列表(当新文章发布时可以后台更新)。
- Pages Router 实现: 在
getStaticProps
的返回值中添加revalidate: number
。 - App Router 实现: 在 Server Component 中使用
fetch
获取数据时,可以配置缓存行为。默认情况下fetch
会自动缓存请求结果,并可以使用next: { revalidate: number }
来指定缓存过期时间,实现类似 ISR 的效果。
总结渲染策略:
选择哪种策略取决于页面内容的特性:
- SSG (或 App Router 中的默认 Server Components): 最佳性能和 SEO,适用于静态或不常更新的内容。
- SSR (或 App Router 中的动态 Server Components/Route Handlers): 适用于需要实时数据或用户特定内容的页面,兼顾性能和 SEO。
- CSR (或 App Router 中的 Client Components): 适用于强交互、对 SEO 和首屏不敏感的页面。
- ISR: SSG 的优化,适用于需要定时更新静态内容的场景。
Next.js 的强大之处在于,你可以在同一个应用中为不同的页面选择不同的渲染策略。
核心概念三:数据获取
数据获取是 Web 应用不可或缺的一部分。Next.js 提供了一套与渲染策略紧密结合的数据获取方式。
Pages Router 中的数据获取函数:
getStaticProps
: (用于 SSG) 在构建时在服务器端运行。无法访问请求相关信息。返回props
会传递给页面组件。getStaticPaths
: (用于 SSG 动态路由) 在构建时在服务器端运行。定义需要预渲染的动态路径。getServerSideProps
: (用于 SSR) 在每次请求时在服务器端运行。可以访问请求相关信息。返回props
会传递给页面组件。- 客户端数据获取: 在页面组件或组件内部使用
useEffect
配合fetch
或 SWR/React Query 等库进行。
App Router 中的数据获取 (推荐):
App Router 引入了 React Server Components 的概念,改变了数据获取的方式。
- Server Components (默认): 大部分组件默认是 Server Components,它们在服务器上渲染。数据获取可以直接在 Server Components 中进行,无需 Hooks。
- 可以使用原生的
fetch
API,Next.js 会自动对其进行扩展,提供缓存、去重等功能。 - 可以安装并使用任何支持 Node.js 环境的数据获取库(如
axios
, ORMs 等)。 - 默认情况下,
fetch
请求会被缓存,可以使用cache: 'no-store'
禁用缓存实现 SSR 行为,或者使用next: { revalidate: number }
实现 ISR 行为。
- 可以使用原生的
- Client Components (
'use client'
): 需要客户端交互的组件被标记为 Client Components。数据获取通常在useEffect
或事件处理器中进行,或者使用 SWR/React Query 等客户端数据获取库。
示例 (App Router):
“`jsx
// app/products/[id]/page.tsx (这是一个 Server Component)
// 可以在 Server Component 中直接定义 async 函数获取数据
async function getProduct(id: string) {
const res = await fetch(https://.../products/${id}
);
// 默认情况下,fetch 会缓存数据。如需 SSR 行为,使用 cache: ‘no-store’
// const res = await fetch(https://.../products/${id}
, { cache: ‘no-store’ });
// 如需 ISR 行为,使用 revalidate
// const res = await fetch(https://.../products/${id}
, { next: { revalidate: 60 } });
if (!res.ok) {
// 建议根据状态码处理错误
throw new Error(‘Failed to fetch product’);
}
return res.json();
}
// page 组件现在可以直接是一个 async 函数
export default async function ProductPage({ params }: { params: { id: string } }) {
const product = await getProduct(params.id);
return (
{product.name}
{product.description}
Price: ${product.price}
);
}
“`
这种方式使得数据获取代码更接近于组件,提高了代码的可读性和组织性。Server Components 可以在服务器上直接访问数据库或后端服务,无需通过 API 层(尽管 API Routes 仍然有用)。
核心概念四:API Routes (App Router 中的 Route Handlers)
Next.js 允许你在同一个项目中创建前后端代码。API Routes (在 App Router 中称为 Route Handlers) 提供了一种简单的方式来构建你自己的 API 接口,而无需单独搭建一个后端服务器。
Pages Router 中的 API Routes:
- 文件放在
pages/api
目录下。 - 每个文件导出一个默认的异步函数,该函数接收
req
(request) 和res
(response) 对象,类似于 Node.js 的 Express 或 Koa 中间件。 - 文件名决定了 API 的路径。
-
示例 (
pages/api/hello.ts
):“`typescript
import type { NextApiRequest, NextApiResponse } from ‘next’;type Data = {
name: string;
};export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
res.status(200).json({ name: ‘John Doe’ });
}
``
/api/hello` 访问。
这个 API 可以通过
App Router 中的 Route Handlers:
- 文件放在
app
目录下的route.ts
或route.js
文件中。 - 与页面文件 (
page.tsx
) 不同,route.ts
不返回 React 组件,而是处理 HTTP 请求。 - 你可以在
route.ts
文件中导出不同的 HTTP 方法的处理函数(GET
,POST
,PUT
,DELETE
,PATCH
,HEAD
,OPTIONS
)。 -
示例 (
app/api/users/route.ts
):“`typescript
// 这是 App Router 中的 API 路由,称为 Route Handler
import { NextResponse } from ‘next/server’;export async function GET() {
// 模拟从数据库获取数据
const users = [
{ id: 1, name: ‘Alice’ },
{ id: 2, name: ‘Bob’ },
];return NextResponse.json(users);
}export async function POST(request: Request) {
const data = await request.json();
// 模拟向数据库添加用户
console.log(‘Received user data:’, data);return NextResponse.json({ message: ‘User created’, user: data }, { status: 201 });
}
``
/api/users` 访问,支持 GET 和 POST 请求。
这个 API 可以通过
API Routes 或 Route Handlers 非常适合用于:
- 构建供客户端或 Server Components 调用的后端 API。
- 处理表单提交。
- 与数据库或外部服务交互。
- 实现身份验证逻辑。
核心概念五:样式处理
Next.js 对样式提供了很好的支持,你可以选择多种方式:
-
CSS Modules (推荐):
- 创建以
.module.css
结尾的文件(例如styles/Home.module.css
)。 - 导入样式时,样式类名会被自动哈希化,实现局部作用域,避免样式冲突。
-
示例:
css
/* styles/Button.module.css */
.button {
padding: 10px 20px;
background-color: blue;
color: white;
}
“`jsx
// components/MyButton.tsx
import styles from ‘../styles/Button.module.css’;function MyButton() {
return ;
}
“`
- 创建以
-
全局 CSS:
- 在
app
目录下的globals.css
(App Router) 或pages/_app.tsx
(Pages Router) 中导入全局 CSS 文件。 - 全局 CSS 会影响整个应用。通常用于重置样式、定义全局变量或引入第三方 CSS 库。
- 注意: 在 Pages Router 中,全局 CSS 只能在
_app.tsx
中导入。
- 在
-
Styled JSX (内置):
- Next.js 内置支持 Styled JSX,一种 CSS-in-JS 库,允许你在组件内部使用
jsx
属性编写带作用域的 CSS。 - 示例:
jsx
function MyComponent() {
return (
<div>
<p>Hello, Styled JSX!</p>
<style jsx>{`
p {
color: purple;
font-size: 18px;
}
`}</style>
</div>
);
}
- Next.js 内置支持 Styled JSX,一种 CSS-in-JS 库,允许你在组件内部使用
-
预处理器 (Sass):
- 安装
sass
包,然后可以直接导入.scss
或.sass
文件。Next.js 会自动编译。
- 安装
-
第三方 CSS-in-JS 库:
- 你可以集成像 Styled Components, Emotion 等流行的 CSS-in-JS 库。通常需要在
pages/_app.tsx
或 App Router 的根布局中进行一些初步设置。
- 你可以集成像 Styled Components, Emotion 等流行的 CSS-in-JS 库。通常需要在
对于大多数情况,CSS Modules 是一个很好的起点,它提供了模块化和避免冲突的优势。
核心概念六:图片优化 (next/image)
图片是网页性能的重要杀手。Next.js 提供了一个 <Image>
组件 (next/image
),它会自动为你优化图片,包括:
- 延迟加载 (Lazy Loading): 图片只在进入视口时加载。
- 响应式图片: 根据用户设备和屏幕尺寸自动加载不同尺寸的图片,节省带宽。
- 图片格式优化: 支持现代图片格式(如 WebP),并自动转换。
- 图片大小优化: 在服务器端按需调整图片尺寸。
- 防止布局偏移 (Layout Shift): 自动处理图片尺寸,减少 CLS (Cumulative Layout Shift)。
使用 <Image>
组件代替原生的 <img>
标签是提升性能的关键优化之一。
示例:
“`jsx
import Image from ‘next/image’;
import profilePic from ‘../public/profile.jpg’; // 支持导入本地图片
function Profile() {
return (
);
}
“`
其他重要概念
- Fast Refresh: Next.js 内置的快速刷新功能,可以在编辑 React 组件时即时看到更改,保持组件状态,极大地提升开发效率。
- 环境变量: Next.js 支持
.env.local
等文件来配置环境变量,这些变量可以在服务器端和客户端访问(以NEXT_PUBLIC_
开头)。 - Middleware (中间件): 允许你在请求完成之前运行代码,例如重定向、修改请求/响应头、身份验证等。可以在项目根目录下创建
middleware.ts
文件。 - TypeScript 支持: Next.js 对 TypeScript 提供了优秀的内置支持,提供了更好的开发体验和代码健壮性。
部署 Next.js 应用
部署 Next.js 应用非常简单,尤其是使用 Vercel (Next.js 的创建者公司提供的平台)。
- Vercel: 将你的 Next.js 项目连接到 Vercel 仓库,Vercel 会自动检测是 Next.js 项目并进行优化部署,包括构建、托管静态文件、配置 serverless functions (用于 SSR 和 API Routes/Route Handlers)。每次 Git Push 都会触发自动部署。
- Static Export: 你可以使用
next export
命令将 Next.js 应用导出为完全静态的 HTML、CSS 和 JS 文件。这种方式只能用于那些完全使用 SSG 的页面,不能包含 SSR 或 API Routes。导出后可以部署到任何静态文件托管服务。 - Node.js Server: 你也可以构建 Next.js 应用 (
next build
),然后使用next start
命令在自己的 Node.js 服务器上运行。
总结与下一步
通过本文的介绍,你应该对 Next.js 的核心概念有了初步的理解:
- 它是一个基于 React 的全栈框架,解决了传统客户端渲染的痛点。
- 基于文件系统的路由让页面创建变得直观。
- 灵活的渲染策略 (SSG, SSR, CSR, ISR) 允许你根据需求优化性能和 SEO。
- 强大的数据获取方式与渲染策略紧密集成。
- API Routes / Route Handlers 让你可以在同一个项目中构建后端接口。
- 内置的样式、图片优化等功能提升了开发效率和应用性能。
掌握这些核心概念,你已经迈出了 Next.js 开发的第一步。
下一步建议:
- 动手实践: 尝试使用
create-next-app
创建一个新项目,并实践本文中介绍的路由、创建页面、尝试不同的数据获取方式。 - 深入 App Router: 详细阅读 Next.js 官方文档关于 App Router 的部分,理解 Server Components, Client Components, Data Fetching in App Router 等新概念。
- 学习 Pages Router (作为补充): 如果你需要维护旧项目或想更全面了解 Next.js,也可以学习 Pages Router 的细节,理解
_app
,_document
,getStaticProps
,getServerSideProps
等。 - 探索更多功能: 学习 Next.js 的更多高级功能,如 Middleware, Authentication, Deploying Strategies, Customizing
next.config.js
等。 - 构建小型项目: 通过构建一个真实的、小型的 Next.js 项目来巩固知识,例如一个简单的博客、产品展示网站或待办事项应用。
Next.js 社区活跃,文档详尽,是学习和构建现代 Web 应用的绝佳选择。祝你在 Next.js 的世界里探索愉快,构建出色的应用!