当前位置: 首页 > backend >正文

Next.js 快速上手指南

1. 概念

Next.js 是一款基于 React 的 Web 开发框架。React 是一个用于构建用户界面的 JavaScript 库,而 Next.js 则在 React 的基础上提供了更多功能,如服务器端渲染(SSR)、静态生成(SSG)等,帮助开发者更高效地构建 Web 应用。

2. 项目搭建

搭建 Next.js 项目的脚手架命令如下:

npx create-next-app@latest

运行命令后,你会看到以下配置选项:

  • 项目名称What is your project named?
  • 是否使用 TypeScriptWould you like to use TypeScript? (推荐使用,有助于类型检查和代码提示)
  • 代码规范工具Which linter would you like to use? (推荐使用 ESLint,用于检查代码规范)
  • 是否使用 Tailwind CSSWould you like to use Tailwind CSS? (推荐使用,方便快速开发响应式布局)
  • 代码是否放在 src/ 目录Would you like your code inside a src/ directory? (推荐放在 src/ 目录,有助于项目结构清晰)
  • 是否使用 App RouterWould you like to use App Router? (推荐使用,这是 Next.js 的新一代路由系统)
  • 是否使用 TurbopackWould you like to use Turbopack? (推荐使用,这是一个新的打包工具,可以提高构建速度)

3. 项目结构

Next.js 的项目结构与 Vue 类似。在第一次运行开发服务器时,你可能需要对 layout.tsx 文件进行一些调整。例如,如果你在国内,可能需要注释掉以下代码,因为这些是谷歌的字体,没有 VPN 的情况下加载会很慢:

const geistSans = Geist({variable: "--font-geist-sans",subsets: ["latin"],
});const geistMono = Geist_Mono({variable: "--font-geist-mono",subsets: ["latin"],
});<bodyclassName={`${geistSans.variable} ${geistMono.variable} antialiased`}
>{children}
</body>

注释掉 ${geistSans.variable} ${geistMono.variable} 部分即可。

4. 组件

组件是可复用的代码块,通常是一个函数。以 page.tsx 为例,function Home 里的 return 返回的是一个 HTML 模板。

你可以在同一个文件中创建自己的组件,例如一个按钮组件:

function Button() {return (<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition">Click Me</button>);
}

然后在页面的其他地方通过 <Button /> 来使用它。你也可以在 components 文件夹中新增 .tsx 文件来处理组件,但要注意添加 export default,并在需要使用它的页面中通过 import 导入。

你还可以将页面中的 mainfooter 内容单独提取为组件,如 MyMainMyFooter,以便复用。

父子组件之间可以传递参数。例如,MyButton 组件可以接受一个 children 参数:

export default function Button({ children }: { children: React.ReactNode }) {return (<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition">{children}</button>);
}

使用时:

<MyButton><b>我很帅</b></MyButton>

你也可以传递一个名为 title 的参数:

function MyMain({ title }: { title: string }) {return <div>{title}</div>;
}

使用时:

<MyMain title="hello world" />

在组件的 return 之前,你可以定义自己的逻辑。例如:

function MyMain({ title }: { title: string }) {const newTitle = title + '1234';return <div>{newTitle}</div>;
}

若要在项目中引入远端的线上图片,可以在 next.config.js 中配置如下内容:

const nextConfig = {images: {remotePatterns: [{protocol: 'https',hostname: 'www.baidu.com',},],},
};

5. 路由

动态路由

动态路由是 Next.js 中一个非常强大的功能,它允许你根据 URL 的参数动态地加载页面内容。这对于构建如博客、电商网站等需要根据 ID 或其他参数显示不同内容的页面非常有用。

什么是动态路由?

动态路由允许你定义一个页面模板,该模板可以根据 URL 中的参数动态加载不同的内容。例如,你有一个博客网站,每个博客文章都有一个唯一的 ID。你可以使用动态路由来创建一个页面模板,该模板可以根据文章 ID 显示不同的文章内容。

示例

假设你有一个博客文章页面,每个文章都有一个唯一的 ID。你可以这样设置动态路由:
文件目录详细配置

  1. 创建动态路由文件夹:在 app 文件夹下创建一个名为 [id] 文件夹(文件夹就叫[id]这个名字),其中 id 是动态参数的名称,如1、2、3、4等。

  2. 创建页面文件:在 [id] 文件夹下创建一个 page.tsx 文件。这个文件将作为动态页面的模板。

// app/[id]/page.tsx
import { notFound } from 'next/navigation';export default async function PostPage({ params }: { params: { id: string } }) {const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);if (!res.ok) {notFound(); // 如果请求失败,返回 404 页面}const post = await res.json();return (<div><h1>{post.title}</h1><p>{post.body}</p></div>);
}

在这个例子中,params.id 是从 URL 中提取的动态参数。当用户访问 /1/2 等路径时,Next.js 会自动将 12 等值传递给 params.id,然后根据这个 ID 获取相应的文章内容。

每个组件的 layout

layout 是 Next.js 中用于定义页面布局的组件。它允许你为一组页面共享相同的布局结构,例如头部、底部、侧边栏等。每个文件夹可以有自己的 layout,这些 layout 会嵌套在一起,形成一个完整的页面结构。

什么是 layout

layout 是一个 React 组件,它定义了页面的共享结构。你可以在这个组件中放置导航栏、底部栏等公共部分,然后通过 children 属性嵌入具体的页面内容。

示例

假设你有一个博客应用,每个页面都有一个公共的头部和底部。你可以这样设置 layout

  1. 创建根 layout:在 app 文件夹下创建一个 layout.tsx 文件。这个文件定义了整个应用的根布局。
// app/layout.tsx
import React from 'react';export default function RootLayout({ children }: { children: React.ReactNode }) {return (<html lang="en"><body><header><nav><ul><li><a href="/">Home</a></li><li><a href="/about">About</a></li><li><a href="/contact">Contact</a></li></ul></nav></header><main>{children}</main><footer><p>&copy; 2023 My Blog</p></footer></body></html>);
}
  1. 创建子文件夹的 layout:在子文件夹下创建自己的 layout 文件。这些 layout 会嵌套在根 layout 中。
// app/blog/layout.tsx
import React from 'react';export default function BlogLayout({ children }: { children: React.ReactNode }) {return (<section><h1>Blog</h1>{children}</section>);
}
  1. 创建页面文件:在子文件夹下创建具体的页面文件。这些页面文件会自动嵌套在父文件夹的 layout 中。
// app/blog/[id]/page.tsx
import { notFound } from 'next/navigation';export default async function PostPage({ params }: { params: { id: string } }) {const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);if (!res.ok) {notFound();}const post = await res.json();return (<article><h2>{post.title}</h2><p>{post.body}</p></article>);
}

在这个例子中,app/layout.tsx 定义了整个应用的根布局,包括头部和底部。app/blog/layout.tsx 定义了博客部分的布局,包括一个标题。app/blog/[id]/page.tsx 是具体的博客文章页面,它会自动嵌套在 app/blog/layout.tsxapp/layout.tsx 中。

嵌套 layout 的工作原理

当 Next.js 渲染页面时,它会从根目录开始,逐级查找 layout 文件,并将它们嵌套在一起。每个 layout 都会通过 children 属性接收子组件的内容,最终形成一个完整的页面结构。

例如,当你访问 /blog/1 时,Next.js 会按照以下顺序渲染组件:

  1. app/layout.tsx(根布局)
  2. app/blog/layout.tsx(博客布局)
  3. app/blog/[id]/page.tsx(具体文章页面)

最终的页面结构如下:

<html lang="en"><body><header><nav><ul><li><a href="/">Home</a></li><li><a href="/about">About</a></li><li><a href="/contact">Contact</a></li></ul></nav></header><main><section><h1>Blog</h1><article><h2>Post Title</h2><p>Post Body</p></article></section></main><footer><p>&copy; 2023 My Blog</p></footer></body>
</html>

总结

通过动态路由,你可以根据 URL 参数动态加载页面内容,这非常适合构建需要根据参数显示不同内容的页面。而 layout 组件则允许你定义页面的共享结构,通过嵌套 layout,你可以轻松地构建复杂的页面布局。

6. 客户端与服务器端组件

Next.js 默认使用服务器端组件模式(Server Components),即先在服务器端渲染 HTML,然后返回给客户端。

如果你想使用客户端模式,只需要在 page.tsx 的开头写上 'use client' 即可:

'use client'

服务器端组件性能更好,因为它们返回的是 HTML 而不是 JavaScript。但是,一些复杂的动画和交互需要客户端模式来实现。

7. Hooks

Hooks 只能用于客户端模式。常用的有 useStateuseEffect

'use client'
import { useState, useEffect } from "react"export default function NewBlog2() {const [count, setCount] = useState(0);const [input, setInput] = useState('');useEffect(() => {setCount(100);}, []);return (<div><h1>New Blog 2 Page</h1><b>这里是 useState 的相关演示</b><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>add</button><button onClick={() => setCount(count - 1)}>sub</button><br /><input type="text" value={input} onChange={(e) => setInput(e.target.value)} /><p>Input: {input}</p><br /><br /><b>这里是 useEffect 的相关演示</b></div>);
}

这里,count 是一个变量,setCount 是一个函数,用于操作 count。逻辑是 onClick={() => setCount(操作)}

useEffect 用于异步操作或者获取第三方 API 数据。最后的 [] 里面可以放变量,后续只要这个变量修改了就会触发一次 useEffect

8. 数据获取 (Data Fetching)

你可以使用 useEffect 来获取数据:

useEffect(() => {const fetchPost = async () => {const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');const data = await res.json();setPost(data);};fetchPost();
}, []);

或者,你可以直接将整个组件做成异步组件,这样就不需要在开头声明模式了,更加方便快捷:

export default async function BlogPost() {const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');const post = await res.json();return (<div><h1>{post.title}</h1><p>{post.body}</p></div>);
}

9. 后端 API

Next.js 是一个强大的全栈框架,支持后端 API 的开发。你可以参考 Next.js 官方文档中的 Route Handlers。

后端路由与前端路由类似,文件路径决定了 API 的地址。后端文件通常是 .ts 文件,而不是 .tsx 文件。

使用 Axios 实例处理前后端交互

Axios 是一个基于 Promise 的 HTTP 客户端,适用于浏览器和 Node.js,非常适合用于处理前后端交互。你可以在 Next.js 的后端 API 路由中使用 Axios 来发送 HTTP 请求。

首先,确保你已经安装了 Axios:

pnpm install axios

然后,配置一个 Axios 实例,如下所示:

// utils/axios.ts
import axios from 'axios';const request = axios.create({baseURL: 'https://jsonplaceholder.typicode.com', // 设置请求的基础路径timeout: 3000000, // 设置请求超时时间(这个时间因个人而定,up本人喜欢时间长一点呢)
});// 添加请求拦截器
request.interceptors.request.use((config) => {// 在发送请求之前做些什么return config;},(error) => {// 对请求错误做些什么return Promise.reject(error);}
);// 添加响应拦截器
request.interceptors.response.use((response) => {// 2xx 范围内的状态码都会触发该函数。// 对响应数据做点什么return response.data; // 直接返回响应数据},(error) => {// 超出 2xx 范围的状态码都会触发该函数。// 对响应错误做点什么console.error('Request failed:', error);return Promise.reject(error);}
);export default request;

接下来,你可以使用这个配置好的 Axios 实例来处理 API 请求。

创建一个简单的 API
// app/api/blog/route.ts
import request from '@/utils/axios';
import { NextResponse } from 'next/server';export async function GET(request: Request) {try {const data = await request.get('/posts/1'); // 使用配置好的 Axios 实例return NextResponse.json(data);} catch (error) {console.error('Error fetching data:', error);return NextResponse.json({ error: 'Failed to fetch data' }, { status: 500 });}
}

这个 API 的路径将是 http://localhost:3000/api/blog

其中,return NextResponse.json(data) 用于将数据以 JSON 格式返回给客户端。它会自动设置响应的 Content-Typeapplication/json,并默认将状态码设置为 200(请求成功)。如果需要,你还可以通过传递一个选项对象来设置其他状态码,例如 return NextResponse.json({ error: 'Not found' }, { status: 404 }) 用于表示资源未找到。

添加更多的 HTTP 方法

你可以根据需要添加更多的 HTTP 方法,如 POSTPUTDELETE 等:

// app/api/blog/route.ts
import request from '@/utils/axios';
import { NextResponse } from 'next/server';export async function GET(request: Request) {try {const data = await request.get('/posts/1'); // 使用配置好的 Axios 实例return NextResponse.json(data);} catch (error) {console.error('Error fetching data:', error);return NextResponse.json({ error: 'Failed to fetch data' }, { status: 500 });}
}export async function POST(request: Request) {try {const data = await request.json();const response = await request.post('/posts', data); // 使用配置好的 Axios 实例return NextResponse.json({ message: 'Data received', data: response });} catch (error) {console.error('Error posting data:', error);return NextResponse.json({ error: 'Failed to post data' }, { status: 500 });}
}

使用 Axios 实例的优势

  1. 简洁易用:Axios 提供了简洁的 API,易于上手和使用。
  2. 功能强大:支持请求和响应拦截器,可以方便地处理请求和响应数据。
  3. 跨浏览器兼容:在各种浏览器环境中都能稳定运行。
  4. 支持 Promise:基于 Promise 的设计,使得异步请求更加方便。
  5. 统一配置:通过配置 Axios 实例,可以统一管理请求和响应的处理逻辑,减少重复代码。

示例:使用 Axios 实例创建一个动态路由 API

假设你有一个博客应用,每个博客文章都有一个唯一的 ID。你可以使用 Axios 实例来创建一个动态路由 API,根据文章 ID 获取文章内容:

// app/api/blog/[id]/route.ts
import request from '@/utils/axios';
import { NextResponse } from 'next/server';export async function GET(request: Request, { params }: { params: { id: string } }) {try {const { data } = await request.get(`/posts/${params.id}`); // 从外部 API 解构获取数据return NextResponse.json(data); // 将数据以 JSON 格式返回给前端} catch (error) {console.error('Error fetching post:', error);return NextResponse.json({ error: 'Post not found' }, { status: 404 });}
}

这个 API 的路径将是 http://localhost:3000/api/blog/1,其中 1 是动态参数 id 的值。

前端调用 API 并渲染数据

接下来,我们将在 Next.js 的前端页面中调用这个 API 并渲染数据。假设你有一个页面组件 BlogPostPage,它根据文章 ID 获取文章内容并渲染。

创建前端页面组件
// app/blog/[id]/page.tsx
import { useParams } from 'next/navigation';
import { useEffect, useState } from 'react';
import request from '@/utils/axios';export default function BlogPostPage() {const { id } = useParams(); // 获取动态参数 idconst [post, setPost] = useState(null);useEffect(() => {async function fetchPost() {try {const response = await request.get(`http://localhost:3000/api/blog/${id}`); // 调用后端 APIsetPost(response);} catch (error) {console.error('Error fetching post:', error);}}if (id) {fetchPost();}}, [id]);if (!post) {return <div>Loading...</div>;}return (<div><h1>{post.title}</h1><p>{post.body}</p></div>);
}

说明

  1. 获取动态参数

    • 使用 useParams 钩子从 Next.js 的路由中获取动态参数 id
  2. 调用后端 API

    • 使用之前配置好的 Axios 实例 request 来调用后端 API。
    • useEffect 中调用 API,并将返回的数据存储在状态 post 中。
  3. 渲染数据

    • 如果 post 数据尚未加载完成,显示一个加载中的提示。
    • 一旦数据加载完成,渲染文章的标题和内容。

完整的前端页面代码

// app/blog/[id]/page.tsx
import { useParams } from 'next/navigation';
import { useEffect, useState } from 'react';
import request from '@/utils/axios';export default function BlogPostPage() {const { id } = useParams(); // 获取动态参数 idconst [post, setPost] = useState(null);useEffect(() => {async function fetchPost() {try {const response = await request.get(`http://localhost:3000/api/blog/${id}`); // 调用后端 APIsetPost(response);} catch (error) {console.error('Error fetching post:', error);}}if (id) {fetchPost();}}, [id]);if (!post) {return <div>Loading...</div>;}return (<div><h1>{post.title}</h1><p>{post.body}</p></div>);
}

10. 总结

通过以上内容,你应该能够快速上手 Next.js,并开始构建自己的 Web 应用。Next.js 提供了许多强大的功能,如服务器端渲染、静态生成和后端 API 开发,能够帮助你构建高性能、可扩展的 Web 应用。

希望这篇指南对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。


以上是完整的 Next.js 快速上手指南,涵盖了从项目搭建到后端 API 开发的各个方面。如果你还有其他需要补充或修改的地方,请随时告诉我。

http://www.xdnf.cn/news/19224.html

相关文章:

  • 数值分析——算法的稳定性
  • 【ACP】2025-最新-疑难题解析- 练习二汇总
  • 文档转换总出错?PDF工具免费功能实测
  • Docker 部署深度网络模型(Flask框架思路)
  • Intellij IDEA社区版(下载安装)
  • 项目管理方法全流程解析
  • HarmonyOS 持久化存储:PersistentStorage 实战指南
  • 详解推测性采样加速推理的算法逻辑
  • nginx配置websock请求,wss
  • java中的VO、DAO、BO、PO、DO、DTO
  • 【重学 MySQL】九十三、MySQL的字符集的修改与底层原理详解
  • 项目管理和产品管理的区别
  • 【gflags】安装与使用
  • 2025 批量下载雪球和东方财富帖子和文章导出excel和pdf
  • 一体化步进伺服电机在视觉检测设备中的应用案例
  • 弱内存模型和强内存模型架构(Weak/Strong Memory Model)
  • vue3多个el-checkbox勾选框设置必选一个
  • 一款支持动态定义路径的JAVA内存马维权工具Agenst
  • 科普文章:广告技术平台的盈利模式全景
  • 2025 批量下载hasmart所有知乎回答,文章和想法,导出txt,html和pdf
  • 指纹云手机网络环境隔离技术:筑牢海外社媒多账号运营安全屏障
  • 计算机--网络编程
  • Flutter 跨平台开发环境搭建指南
  • CVPR深度学习论文创新合集拆解:模型训练速度算提升
  • 数据库原理及应用_数据库基础_第3章数据库编程_常用系统函数
  • QWidget和QML模式下阻止槽调用的方法总结
  • 复现论文块体不锈钢上的光栅耦合表面等离子体共振
  • 【杂谈】-混沌理论能否赋予机器差异化思考能力?
  • vscode+cmake+mingw64+opencv环境配置
  • 《HM-RAG: Hierarchical Multi-Agent Multimodal Retrieval Augmented Generation》