Next.js 快速入门:构建你的第一个应用
欢迎来到 Next.js 的世界!如果你是 React 开发者,并且希望构建功能强大、性能卓越、对搜索引擎友好且开发体验极佳的应用,那么 Next.js 无疑是一个非常棒的选择。它是一个基于 React 的全栈 Web 框架,提供了服务端渲染 (SSR)、静态网站生成 (SSG)、路由、API 路由、代码分割等一系列开箱即用的功能,极大地简化了现代 Web 应用的开发流程。
本文将手把手带你迈出 Next.js 的第一步,从零开始创建一个 Next.js 应用,了解其核心概念,并构建一个简单的页面和组件。
为什么选择 Next.js?
在深入实践之前,我们先快速了解一下 Next.js 的主要优势:
- 服务端渲染 (SSR) 和静态网站生成 (SSG):Next.js 支持多种渲染模式,可以根据需要选择 SSR(动态内容)、SSG(静态内容)或客户端渲染 (CSR)。这有助于提高应用性能、改善用户体验,并对 SEO 非常友好。
- 文件系统路由:通过创建文件和文件夹来定义应用的路由,直观且易于管理。
- API 路由:可以在 Next.js 项目内部轻松创建 API 端点,无需单独的后端服务。
- 代码分割和优化:Next.js 会自动进行代码分割,只加载当前页面所需的 JavaScript 代码,提升页面加载速度。同时还内置了图片优化、字体优化等功能。
- 优秀开发者体验:提供快速刷新(Fast Refresh)、内置 CSS 支持、TypeScript 支持、ESLint 等,让开发更加高效愉快。
- 强大的社区和生态:作为流行的框架,Next.js 拥有庞大的社区支持和丰富的第三方库。
前置准备
在开始之前,请确保你的开发环境中已安装以下工具:
- Node.js: 建议安装 LTS (长期支持) 版本。你可以访问 Node.js 官网 下载安装。
- npm, yarn 或 pnpm: Node.js 安装后会自带 npm。你也可以选择安装 yarn 或 pnpm 作为包管理器。
- 代码编辑器: 如 VS Code, Sublime Text, WebStorm 等。
- 基础 React 知识: 虽然 Next.js 帮你处理了很多底层细节,但理解 React 的组件、Props、State、Hooks 等概念是必要的。
第一步:创建你的第一个 Next.js 应用
创建 Next.js 应用最推荐的方式是使用官方提供的 create-next-app
脚手架工具。它会为你设置好一个基础的项目结构和必要的配置。
打开你的终端或命令行工具,运行以下命令:
bash
npx create-next-app@latest
这个命令会使用最新版本的 create-next-app
。运行后,它会引导你进行一系列配置选择:
√ What is your project named? ... my-next-app # 项目名称
√ Would you like to use TypeScript? ... Yes/No # 是否使用 TypeScript (强烈推荐使用 TypeScript)
√ Would you like to use ESLint? ... Yes/No # 是否使用 ESLint (推荐使用,用于代码规范检查)
√ Would you like to use Tailwind CSS? ... Yes/No # 是否使用 Tailwind CSS (流行的原子化 CSS 框架,可根据喜好选择)
√ Would you like to use `src/` directory? ... Yes/No # 是否使用 src/ 目录来组织代码 (推荐使用,结构更清晰)
√ Use App Router (recommended)? ... Yes/No # 是否使用 App Router (这是 Next.js 13+ 推出的新路由系统,也是官方推荐的未来方向,我们将基于 App Router 进行讲解)
√ Would you like to customize the default import alias (@/*)? ... Yes/No # 是否自定义导入别名 (默认是 @/*,方便导入 src 目录下的模块)
按照你的偏好进行选择。对于本教程,我们选择:
- 项目名称:
my-next-app
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: No (为了简化,我们使用普通的 CSS 或 CSS Modules)
src/
directory: Yes- App Router: Yes
- Import alias: No (使用默认的
@/*
)
选择完成后,create-next-app
会自动创建项目目录、安装必要的依赖。这个过程可能需要几分钟。
安装完成后,进入项目目录:
bash
cd my-next-app
现在,运行开发服务器:
“`bash
npm run dev
或者 yarn dev
或者 pnpm dev
“`
稍等片刻,终端会显示类似以下信息:
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
打开你的浏览器,访问 http://localhost:3000
,你将看到 Next.js 的默认启动页面。恭喜你,你的第一个 Next.js 应用已经成功运行起来了!
第二步:理解项目结构 (App Router)
使用 create-next-app
创建的项目结构可能会根据你的选择略有不同,但核心目录和文件是类似的。由于我们选择了 App Router 并使用了 src/
目录,你的项目结构大致如下:
my-next-app/
├── node_modules/
├── public/ # 存放静态资源,如图片、字体等,可以直接通过根路径访问
├── src/
│ ├── app/ # App Router 的核心目录
│ │ ├── favicon.ico # 应用图标
│ │ ├── global.css # 全局 CSS 文件
│ │ ├── layout.tsx # 根布局文件,定义 HTML 结构和共享 UI
│ │ └── page.tsx # 应用的根页面 (对应 / 路径)
│ └── app/globals.css # 或者全局样式在 src/globals.css
├── .eslintrc.json # ESLint 配置文件
├── .gitignore # Git 忽略文件
├── next-env.d.ts # Next.js 环境变量的 TypeScript 类型定义
├── next.config.js # Next.js 配置文件
├── package.json # 项目依赖和脚本
├── README.md # 项目说明文件
├── tsconfig.json # TypeScript 配置文件
app/
目录: 这是 App Router 的核心。所有路由、布局、页面、加载状态、错误边界等都在这个目录下定义。page.tsx
: 在一个路由段中,page.tsx
(或.js
,.jsx
) 文件是该路由段的入口文件,它默认导出的是一个 React 组件,渲染该路由的 UI。例如,app/page.tsx
对应/
路径,app/about/page.tsx
对应/about
路径。layout.tsx
: 在一个路由段中,layout.tsx
文件定义了该路由段及其子路由段的布局。根目录下的app/layout.tsx
是整个应用的根布局,通常在这里定义<html>
,<body>
标签以及共享的导航、页脚等。global.css
: 用于定义全局样式。public/
: 存放不需要经过 Webpack 处理的静态资源,例如图片、字体、robots.txt
等。这些文件可以直接通过项目的根 URL 访问(例如/favicon.ico
对应public/favicon.ico
)。next.config.js
: Next.js 的配置文件,用于进行更高级的配置,例如环境变量、自定义 Webpack 配置等。
第三步:创建新页面和导航
Next.js 的文件系统路由非常直观。只需在 app
目录下创建文件夹和 page.tsx
文件即可。
创建 “关于我们” 页面
- 在
src/app
目录下创建一个新文件夹,命名为about
。 - 在
src/app/about
目录下创建一个新文件,命名为page.tsx
。 -
打开
src/app/about/page.tsx
,添加以下内容:“`tsx
// src/app/about/page.tsxexport default function AboutPage() {
return (
关于我们
这是一个关于我们的页面,使用 Next.js 构建。
);
}
“`
保存文件。现在,访问 http://localhost:3000/about
,你将看到你创建的 “关于我们” 页面。就是这么简单!
创建导航链接
为了方便用户在页面之间切换,我们需要添加导航链接。在 Next.js 中,我们使用内置的 <Link>
组件来处理客户端导航。使用 <Link>
的好处是它会自动处理预加载(prefetching),在用户可能点击链接之前提前加载目标页面的代码,从而加快页面切换速度。
-
修改
src/app/page.tsx
,添加一个到 “关于我们” 页面的链接:“`tsx
// src/app/page.tsx
import Link from ‘next/link’; // 导入 Link 组件
import Image from ‘next/image’;
import styles from ‘./page.module.css’; // 假设存在这个样式文件,create-next-app 会生成export default function Home() {
return (
Get started by editing
src/app/page.tsx
<div className={styles.center}> {/* ... 其他内容 ... */} </div> <div className={styles.grid}> {/* ... 其他链接 ... */} </div> {/* 添加一个到关于页面的链接 */} <div style={{ marginTop: '2rem' }}> <Link href="/about"> 点击前往关于我们页面 </Link> </div> </main>
);
}
``
create-next-app` 默认生成的一些内容,你可以在其中找到合适的位置添加你的链接)
(注意:上面的代码包含了 -
修改
src/app/about/page.tsx
,添加一个回到首页的链接:“`tsx
// src/app/about/page.tsx
import Link from ‘next/link’; // 导入 Link 组件export default function AboutPage() {
return (
关于我们
这是一个关于我们的页面,使用 Next.js 构建。
{/* 添加一个回到首页的链接 */} <div style={{ marginTop: '1rem' }}> <Link href="/"> 返回首页 </Link> </div> </main>
);
}
“`
保存文件。现在你可以在首页和关于页面之间轻松导航了。
第四步:理解 Server Components 和 Client Components
Next.js 13+ App Router 的一个重要特性是引入了 React Server Components (RSC)。默认情况下,app
目录下的所有组件都是 Server Components。
Server Components (服务器组件)
- 默认类型。
- 在服务器上渲染,不包含 JavaScript。
- 可以直接访问文件系统、数据库或内部 API。
- 不支持状态 (State) 和副作用 (Effects) (如
useState
,useEffect
)。 - 更小的客户端 Bundle 体积,有助于提升性能。
Client Components (客户端组件)
- 需要通过在文件顶部添加
'use client';
指令来标记。 - 在浏览器中渲染,包含 JavaScript。
- 可以访问浏览器 API (如
window
,localStorage
)。 - 支持交互功能,可以使用状态和副作用。
何时使用哪种?
- Server Components: 适合渲染不依赖用户交互或浏览器 API 的静态或动态内容,例如显示博客文章、产品列表、从数据库获取数据等。它们可以减少客户端的 JavaScript 负担。
- Client Components: 适合需要用户交互或访问浏览器特定功能的组件,例如带有点击事件的按钮、表单输入、动画、使用 Hooks (
useState
,useEffect
) 的组件等。
示例:创建一个 Client Component
让我们创建一个简单的计数器组件,它需要使用 useState
,因此必须是一个 Client Component。
- 在
src/app
目录下创建一个新文件夹,命名为components
。 - 在
src/app/components
目录下创建一个新文件,命名为Counter.tsx
。 -
打开
src/app/components/Counter.tsx
,添加以下内容:“`tsx
// src/app/components/Counter.tsx
‘use client’; // 👈 标记这是一个客户端组件import { useState } from ‘react’; // 可以在客户端组件中使用 Hooks
export default function Counter() {
const [count, setCount] = useState(0);return (
计数: {count}
);
}
“` -
现在,在
src/app/page.tsx
(这是一个 Server Component) 中导入并使用这个 Client Component:“`tsx
// src/app/page.tsx
import Link from ‘next/link’;
import Image from ‘next/image’;
// import styles from ‘./page.module.css’; // 根据你的项目选择是否保留
import Counter from ‘./components/Counter’; // 导入客户端组件export default function Home() {
return (
欢迎来到我的 Next.js 应用!
这是一个首页。
{/* 在服务器组件中渲染客户端组件 */} <Counter /> <div style={{ marginTop: '2rem' }}> <Link href="/about"> 点击前往关于我们页面 </Link> </div> </main>
);
}
“`
保存文件,刷新首页,你将看到并可以与计数器交互了。
重要概念: Server Components 可以导入和渲染 Client Components,但 Client Components 不能直接导入和使用 Server Components。如果你需要在 Client Component 中使用 Server Component 渲染的内容,可以将 Server Component 的内容作为 props 传递给 Client Component,或者利用 composition patterns (组合模式)。
第五步:添加样式
Next.js 支持多种样式方案,包括全局 CSS、CSS Modules、CSS-in-JS 库以及与 Tailwind CSS 集成 (如果你在 setup 时选择了)。
全局样式
src/app/global.css
是放置全局样式的地方。你可以直接在这里编写 CSS,或者导入其他 CSS 文件。
“`css
/ src/app/global.css /
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1 {
color: #333;
}
“`
CSS Modules
CSS Modules 可以很好地解决 CSS 全局污染的问题,它会为你的类名生成唯一的哈希值。文件名需要以 .module.css
结尾。
-
在
src/app
或src/app/ui
(如果你创建了 UI 组件目录) 下创建一个新的 CSS Modules 文件,例如src/app/ui/Button.module.css
:“`css
/ src/app/ui/Button.module.css /
.button {
padding: 10px 20px;
background-color: #0070f3;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
}.button:hover {
background-color: #0050c0;
}
“` -
创建一个使用这个样式的 React 组件,例如
src/app/ui/Button.tsx
:“`tsx
// src/app/ui/Button.tsx
// 这个组件可以是一个 Client Component 如果需要交互
// 如果只是用于样式展示,可以是 Server Component
// 我们在这里为了演示方便,让它成为一个 Client Component
‘use client’;import styles from ‘./Button.module.css’; // 导入 CSS Modules
interface ButtonProps {
children: React.ReactNode;
onClick?: () => void;
}export default function Button({ children, onClick }: ButtonProps) {
return (
);
}
“` -
在你的页面 (
page.tsx
或about/page.tsx
) 中导入并使用这个按钮组件:“`tsx
// src/app/page.tsx
// … 其他导入 …
import Button from ‘./ui/Button’; // 导入带 CSS Modules 的按钮组件export default function Home() {
return (
欢迎来到我的 Next.js 应用!
这是一个首页。
<Counter /> <div style={{ marginTop: '1rem' }}> {/* 使用 Button 组件 */} <Button onClick={() => alert('按钮被点击了!')}> 一个带样式的按钮 </Button> </div> <div style={{ marginTop: '2rem' }}> <Link href="/about"> 点击前往关于我们页面 </Link> </div> </main>
);
}
“`
现在,你就有了一个使用 CSS Modules 样式化的按钮。
第六步:数据获取 (Data Fetching)
在 Next.js 的 App Router 中,推荐在 Server Components 中进行数据获取。这使得你可以在渲染组件之前就获取到所需的数据,从而提升性能和用户体验。
Next.js 扩展了原生的 fetch
API,提供了强大的缓存和去重能力。
示例:在首页获取数据
让我们在首页获取一个简单的用户列表,并展示出来。我们将使用 JSONPlaceholder 提供的免费 API。
修改 src/app/page.tsx
文件:
“`tsx
// src/app/page.tsx
import Link from ‘next/link’;
import Image from ‘next/image’;
// import styles from ‘./page.module.css’; // 根据你的项目选择是否保留
import Counter from ‘./components/Counter’; // 导入客户端组件
// 定义用户类型 (如果使用 TypeScript)
interface User {
id: number;
name: string;
username: string;
email: string;
// … 其他属性
}
// 异步 Server Component,用于数据获取
export default async function Home() { // 👈 将组件声明为 async
// 在 Server Component 中直接使用 fetch
const res = await fetch(‘https://jsonplaceholder.typicode.com/users’);
const users: User[] = await res.json();
return (
欢迎来到我的 Next.js 应用!
这是一个首页。
<Counter />
<div style={{ marginTop: '2rem' }}>
<h2>用户列表 (从 API 获取):</h2>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} ({user.email})
</li>
))}
</ul>
</div>
<div style={{ marginTop: '2rem' }}>
<Link href="/about">
点击前往关于我们页面
</Link>
</div>
</main>
);
}
“`
保存文件,刷新首页,你将看到从 API 获取到的用户列表显示出来了。
Next.js 的 fetch
扩展
Next.js 对原生的 fetch
进行了扩展,支持更高级的缓存控制选项:
cache
:'force-cache'
(默认): 尽可能从缓存中获取数据。'no-store'
: 始终重新获取数据,不使用缓存。'only-if-cached'
: 只从缓存中获取,如果缓存中没有则返回 undefined。
next
:{ revalidate: number | false }
: 设置数据的重新验证间隔(秒)。如果设置为false
,则禁用自动重新验证。{ tags: string[] }
: 为请求打标签,以便按标签按需重新验证。
例如,如果你想每隔 60 秒重新验证一次用户数据:
tsx
const res = await fetch('https://jsonplaceholder.typicode.com/users', {
next: { revalidate: 60 } // 每 60 秒重新验证一次
});
const users: User[] = await res.json();
这种在 Server Component 中直接 await fetch
的模式非常强大,它简化了数据获取逻辑,并利用 Next.js 内置的缓存机制提高了性能。
第七步:构建和运行生产版本
开发模式 (npm run dev
) 带有热更新等功能,适合开发调试。但要部署到生产环境,你需要构建一个优化过的版本。
在终端中运行:
“`bash
npm run build
或者 yarn build
或者 pnpm build
“`
这个命令会触发 Next.js 的生产构建过程。它会进行代码优化、生成静态资源、根据你的页面使用 SSR 还是 SSG 来决定渲染方式等。构建完成后,你会看到一个 .next
目录,里面包含了构建后的文件。
终端会输出每个页面的渲染方式(例如,/
是 SSR 或 Static,/about
是 Static)。
构建完成后,你可以运行生产服务器来预览应用:
“`bash
npm start
或者 yarn start
或者 pnpm start
“`
现在,访问 http://localhost:3000
(或其他显示的端口),你看到的就是构建后的生产版本应用了。它通常比开发模式更快,并且已经过优化。
进阶探索
完成第一个 Next.js 应用的基础构建后,你还可以继续探索更多强大的功能:
- 动态路由: 处理带有参数的路由,例如
/posts/[id]
。 - API 路由: 在
src/app/api
目录下创建 RESTful API 端点。 - Loading UI: 使用
loading.tsx
文件为路由段添加加载状态。 - Error Handling: 使用
error.tsx
文件为路由段添加错误边界。 - Static Assets: 如何在
public
目录中放置和使用静态资源。 - Middleware: 在请求到达路由之前运行代码。
- 部署: Next.js 可以轻松部署到 Vercel (由 Next.js 团队开发,提供最佳支持)、Netlify、AWS 等平台。
总结
恭喜你!你已经成功创建、运行并了解了 Next.js 的核心概念,包括:
- 使用
create-next-app
初始化项目。 - 理解 App Router 的文件系统路由 (
app/
,page.tsx
,layout.tsx
)。 - 区分和使用 Server Components 和 Client Components。
- 添加页面间导航 (
<Link>
)。 - 使用全局样式和 CSS Modules。
- 在 Server Component 中进行数据获取 (
fetch
)。 - 构建和运行应用的生产版本。
这只是 Next.js 强大功能的冰山一角。通过不断实践和学习,你可以利用 Next.js 构建出高性能、可伸缩且易于维护的现代 Web 应用。
接下来,你可以尝试:
- 为你的应用添加更多页面和导航。
- 尝试获取不同类型的外部数据。
- 使用 CSS Modules 或 Tailwind CSS (如果安装了) 来美化你的应用。
- 了解如何处理动态路由和 API 路由。
祝你在 Next.js 的学习旅程中一切顺利!