NextJs 初级篇 - 安装 | 路由 | 中间件

NextJs 初级篇 - 安装 | 路由 | 中间件

  • 一. NextJs 的安装
  • 二. 路由
    • 2.1 路由和页面的定义
    • 2.2 布局的定义和使用
    • 2.3 模板的定义和使用
      • ① 模板 VS 布局
      • ② 什么是 use client
    • 2.4 路由跳转的方式
    • 2.5 动态路由
    • 2.6 路由处理程序
      • ① GET 请求的默认缓存机制
      • ② 控制缓存或者退出缓存的手段
      • ③ 控制缓存的时效 revalidate
      • ④ 常见的编写问题
  • 3. 中间件

一. NextJs 的安装

首先,NextJs要想使用,node版本不能太低,最低也要18以上,版本不够的,可以用nvm来管理,Mac用户的安装可以参考这篇文章:
mac 系统正确安装nvm

版本满足的同学,建议直接使用脚手架来创建nextJs,输入脚手架命令(这里又切了阿里的镜像,以防万一关闭SSL认证):

npm config set registry https://registry.npm.taobao.org
npm config set strict-ssl false
npx create-next-app@latest

结果如下:这里我们优先使用App Router(后面会讲解)
在这里插入图片描述
生成结果如下:
在这里插入图片描述
启动项目: npm run dev,之后访问:http://localhost:3000/ 即可

二. 路由

NextJs 拥有两套路由(两者兼容):

  • Pages Router:在pages目录下创建对应的文件或者目录即是一个路由。
  • App RouterNextJs从版本13.4起的默认路由模式

为什么官方在新版本中,默认的路由模式采用了App呢?

  • pages每个文件都会被当成路由,不符合开发习惯
  • app 架构新增了布局(layout)、模版(template)、加载状态(loading)、错误处理(error)、404 等文件,为项目开发提供了一套规范。

2.1 路由和页面的定义

我们这里主要讲官方更推荐的AppRouter,如图:
在这里插入图片描述
这里简单介绍下:

  • 我们约定使用 page 来代表一个页面,就好比React中使用:index。和React一样,默认导出个组件即可。
  • 文件的路径就是对应的路由。
  • app/page.tsx 对应路由 /
  • app/about/page.tsx 对应路由 /about
  • app/address/page.tsx 对应路由 /address
  • 后缀名可以使用:.js、.jsx、.tsx

2.2 布局的定义和使用

首先布局组件有这么几个特征:

  • 定义一个布局,需要新建一个名称为:layout 的固定文件,该组件接收一个children,代表子页面或者子布局。
  • 布局可以嵌套,父布局中有一个子布局。

根布局还有额外几个特征:

  • 定义在app/layout.tsx文件中,会应用于所有的路由。并且此文件必须存在。
  • 根布局文件中必须包含htmlbody标签。同时其他布局不能包含这些标签。

根布局文件内容示例:

import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({children,
}: Readonly<{children: React.ReactNode;
}>) {return (<html lang="en"><body className={inter.className}>{children}</body></html>);
}

布局的嵌套: address 下有个子目录home,每个文件都有自己的layout布局。
在这里插入图片描述
AddressLayout

const AddressLayout = ({ children }: any) => {return (<><nav>我是Address的Layout</nav>{children}</>)
}
export default AddressLayout

HomeLayout

const HomeLayout = ({ children }: any) => {return (<><nav>我是Home的Layout</nav>{children}</>)
}
export default HomeLayout

访问http://localhost:3000/address/home,呈现效果:
在这里插入图片描述

2.3 模板的定义和使用

模板跟布局的用法是一样的,例如我们在address下定义一个固定名称的模板文件:template.tsx

const AddressTemplate = ({ children }: any) => {return (<><nav>我是Address的模板</nav>{children}</>)
}
export default AddressTemplate

此时我们访问 http://localhost:3000/address/home,呈现效果:在这里插入图片描述
这说明了:layout 会包裹 templatetemplate 再包裹 page

那模板和布局之间,存在着什么差异?

① 模板 VS 布局

状态的维持:

  • 模板:路由切换的时候,模板的内容会随之变更。
  • 布局:路由切换的时候,布局的内容不会更改。

框架默认行为的更改:以组件Suspense为例,这个组件就是一个渲染fallback组件效果的功能。

  • 模板:模板内使用Suspense,每次切换路由的时候,都会展示fallback组件
  • 布局:模板内使用Suspense,每次切换路由的时候,只会展示一次。

其实这两个点比较类似,说白了就是,每次在切换路由的时候,使用 template ,就可以重新触发渲染。

来个案例,目录结构如下:
在这里插入图片描述
sonA

const SonA = () => {return <>我是SonA!!!</>
}
export default SonA

sonB

const SonB = () => {return <>我是SonB!!!</>
}
export default SonB

父组件:page.tsx

import Link from "next/link";const Parent = () => {return <><nav>当前页面是父组件</nav><nav>跳转到:<Link href='/parent/sonA'>SonA</Link></nav><nav>跳转到:<Link href='/parent/sonB'>SonB</Link></nav></>
}export default Parent

template.tsx

'use client'
import { useState } from "react"
const AddressTemplate = ({ children }: any) => {const [count, setCount] = useState<number>(0);return (<><h1>Template点击次数: {count}</h1><button onClick={() => setCount(count + 1)}>点击</button>{children}</>)
}
export default AddressTemplate

layout.tsx

'use client'
import { useState } from "react"
const ParentLayout = ({ children }: any) => {const [count, setCount] = useState<number>(0);return (<><h1>Layout点击次数:  {count}</h1><button onClick={() => setCount(count + 1)}>点击</button>{children}</>)
}
export default ParentLayout

结果如下:

在这里插入图片描述

② 什么是 use client

'use client' 是一个指令,放置在文件的顶部(通常是模块的第一行)。它告诉 Nextjs 该模块应该在客户端环境中执行,而不是在服务器端。

备注:默认情况下,NextJs中的页面是由服务端渲染的,即SSR

2.4 路由跳转的方式

在上述案例中,我们使用 Link 组件来完成路由的跳转。而NextJs中,一共支持3种路由跳转的方式:

  • Link 组件。
  • 使用钩子函数:useRouter
  • 使用 redirect 函数

第一种 Link 组件,是最为推荐的方式,例如上述案例中的代码。

<Link href='/parent/sonA'>SonA</Link>

除此之外,还可以更改默认的跳转行为:App Router 的默认行为是滚动到新路由的顶部。可以通过传参 scrollfalse改变。

<Link href='/parent/sonA' scroll={false}>SonA</Link>

第二种使用useRouter函数:

'use client'
import Link from "next/link";
import { useRouter } from 'next/navigation'const Parent = () => {const router = useRouter();return <><nav>当前页面是父组件</nav><nav>跳转到:<Link href='/parent/sonA'>SonA</Link></nav><nav>跳转到:<button onClick={() => router.push('/parent/sonB')}>SonB</button></nav></>
}export default Parent

我们还能发现,一旦使用钩子函数,这种客户端触发的动作,就需要加上标识'use client',代表它是需要客户端渲染。


第三种:redirect,用于给服务端组件用的,伪代码如下:

import { redirect } from 'next/navigation'async function login(id) {const res = await login()if (!res.ok) {redirect('/error')}return res.json()
}

2.5 动态路由

假设我们访问某个订单详情页,订单号可能是动态会变的,这里假设订单号是123456,一般我们可以设计两种URL

  • /orderInfo/123456
  • /orderInfo?orderId=123456

先说第一种,就需要通过动态路由的方式来访问。NextJs中,需要将文件夹的名字用方括号[] 扩住。例如我们创建一个目录:orderInfo/[orderId],代表orderId是一个动态路由,其中这个动态参数可以通过orderId字段来读取。
在这里插入图片描述
然后页面上我们希望把订单号展示出来。其中组件接收一个参数:params,如下:

import React from 'react'
const About = ({ params }: any) => {return <><h1>订单详情页面</h1><span>{params.orderId}</span></>
}
export default About

那么在访问 http://localhost:3000/orderInfo/123 的时候,效果如下:
在这里插入图片描述


那如果我们动态参数后还跟着路由,例如 http://localhost:3000/orderInfo/123/shop 若直接访问我们看看结果:
在这里插入图片描述
我们发现此时404了,可见这种情况下,动态参数[orderId]只会接收第一个路由片段,那怎么办呢?我们可以将[orderId] 改为: [[..orderId]],表示捕获所有后面所有的路由片段。
在这里插入图片描述
例如:
在这里插入图片描述

2.6 路由处理程序

NextJs中,对于客户端和服务端之间的API交互,叫做路由处理程序。

编写一个简单的路由处理程序,规则如下:

  • 接口的路径跟路由比较相似,对应文件目录下创建一个名为 route 的文件即可。
  • 文件中需要导出固定名称的函数(无需使用default exportGET、POST等。
  • 可以使用NextResponse代表返回的数据。
// route.js
export async function GET(request) {}
export async function HEAD(request) {}
export async function POST(request) {}
export async function PUT(request) {}
export async function DELETE(request) {}
export async function PATCH(request) {}
// 如果 `OPTIONS` 没有定义, Next.js 会自动实现 `OPTIONS`
export async function OPTIONS(request) {}

一个简单的GETPOST请求:
在这里插入图片描述
GET请求:

import { NextRequest, NextResponse } from 'next/server'export async function GET() {const data = [{ id: 1, name: 'LJJ' }]return NextResponse.json({ data })
}

对应结果:
在这里插入图片描述
POST请求:

import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {const data = await request.json();return NextResponse.json(data)
}

对应结果:
在这里插入图片描述

① GET 请求的默认缓存机制

默认情况下,使用NextResponse对象的GET请求会被NextJs缓存起来。(本地模式下不会缓存,生产模式则会)

我们改一下我们的getUserList接口:

import { NextResponse } from 'next/server'export async function GET() {const data = [{ id: 1, name: 'LJJ', date: new Date().getMilliseconds() }]return NextResponse.json({ data })
}

然后跑命令: npm run build & npm run start
我们能发现构建产物:/api/getUserList 是静态的。
在这里插入图片描述
我们请求接口发现:无论请求几遍,时间戳永远不会变,是因为被缓存了。
在这里插入图片描述

② 控制缓存或者退出缓存的手段

退出缓存的方式有这么几种:

  • GET 请求中使用了 Request 对象。例如:返回对象依赖于Request的参数。
  • 添加其他 HTTP 方法,比如同一个route文件中,同时定义了GETPOST函数。
  • 使用像 cookiesheaders 这样的动态函数。
  • 也可以手动声明接口为动态模式。 文件顶端增加:export const dynamic = 'force-dynamic' 即可
// 返回结果依赖于request的参数
export async function GET(request: NextRequest) {const searchParams = request.nextUrl.searchParamsconst data = [{ id: 1, name: searchParams.toString(), date: new Date().getMilliseconds() }]return NextResponse.json({ data })
}
// 使用cookies这种动态函数
export async function GET(request) {const token = request.cookies.get('token')return Response.json({ data: new Date().toLocaleTimeString() })
}

③ 控制缓存的时效 revalidate

我们可以在route文件的顶部增加声明,例如以下就是标识缓存的有效期为10秒。

export const revalidate = 10

④ 常见的编写问题

首先是:获取URL上的参数、获取Header、获取Request请求体(JSON)、Cookie

import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {// 获取URL上的参数const searchParams = request.nextUrl.searchParamsconsole.log(searchParams.get('orderId'));// 处理 Headerconst headersList = new Headers(request.headers)const referer = headersList.get('myHeader')console.log(referer)// 获取Request请求体 (JSON)const data = await request.json();// 如果是FormData// const formData = await request.formData()// const name = formData.get('name')return NextResponse.json(data)
}

Postman请求:http://localhost:3000/api/getDetail?orderId=123
在这里插入图片描述
结果如下:
在这里插入图片描述


重定向:使用redirect即可。

import { redirect } from 'next/navigation'export async function POST(request: NextRequest) {redirect('https://www.baidu.com')
}

获取Cookie、并设置到Response中,则需要返回一个使用 Set-Cookie headerResponse 实例

import { cookies } from 'next/headers'export async function POST() {const cookieStore = cookies()const token = cookieStore.get('test')console.log(token)return new Response('OK', {status: 200,headers: { 'Set-Cookie': `myNewToken=${12312312312}` },})
}

请求后:
在这里插入图片描述

3. 中间件

NextJs 中,中间件的定义,可以在根目录中定义一个固定名称的文件:middleware.ts,它的内容有两个部分组成:

// middleware.js
import { NextResponse } from 'next/server'// 第一部分:导出固定名称的中间件
export function middleware(request) {// ... 中间件逻辑
}
// 第二部分:设置匹配路径
export const config = {matcher: '/api/:path*',
}

这里直接给个案例,假设我中间件有多个功能:

  • 中间件 headers:处理相关的Header
  • 中间件 logging:记录相关的日志

我们可以在根目录下创建个专门编写中间件的文件夹:middlewares
在这里插入图片描述
两个中间件内容:

// logging.ts
import { NextRequest } from "next/server";
export const logging = (next: any) => {return async (request: NextRequest) => {// ...console.log('logging')return next(request);};
};
// headers.ts
import { NextRequest } from "next/server";
export const headers = (next: any) => {return async (request: NextRequest) => {console.log('headers')return next(request);};
};

然后我们可以设置下别名,tsconfig.json 文件中:
在这里插入图片描述
这样就可以在真正设置中间件的地方(根路径的middleware.ts中)进行设置:

import { logging } from "@/middlewares/logging";
import { headers } from "@/middlewares/headers";
import { NextResponse } from "next/server";function chain(functions: any, index = 0) {const current = functions[index];if (current) {const next: any = chain(functions, index + 1);return current(next);}return () => NextResponse.next();
}export default chain([logging, headers]);export const config = {matcher: '/api/:path*',
}

这样访问任何一个接口,都会走相关的逻辑了。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/16270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型效能工具之智能CommitMessage

01 背景 随着大型语言模型的迅猛增长&#xff0c;各种模型在各个领域的应用如雨后春笋般迅速涌现。在研发全流程的效能方面&#xff0c;也出现了一系列贯穿全流程的提效和质量工具&#xff0c;比如针对成本较高的Oncall&#xff0c;首先出现了高质量的RAG助手&#xff1b;在开…

山东大学软件学院数据库实验1-9(全部)

目录 前言 实验代码 实验一 1-1 1-2 1-3 1-4 1-5 1-6 实验二 2-1 2-2 2-3 2-4 2-5 2-6 2-7 2-8 2-9 2-10 实验三 3-1 3-2 3-3 3-4 3-5 3-6 3-7 3-8 3-9 3-10 实验四 4-1 4-2 4-3 4-4 4-5 4-6 4-7 4-8 4-9 4-10 实验五 5-1…

鹏特资本进入中国市场具有以下一些优势

1. 带来资金&#xff1a;补充国内资金缺口&#xff0c;为企业发展和项目建设提供重要的资金支持。 2. 先进技术和管理经验&#xff1a;有助于推动技术创新和管理水平提升&#xff0c;促进产业升级和优化。 3. 促进竞争&#xff1a;激发国内市场活力&#xff0c;促使本土企业不…

解决 Failed to parse remote port from server output【Remote-SSH】【VSCode】

描述 一早起来&#xff0c;发现remote-ssh无法进入服务器容器&#xff0c;本地使用git bash进行ssh可正常连接服务器&#xff0c;基本确定是vscode工具本身的问题。重装本地用户的.vscode相关目录清空&#xff0c;vscode重装均无果&#xff0c;不建议尝试。弹窗信息为Could no…

【课程作业】嵌入式系统与设计上机作业(作业三)

个人名片&#xff1a; &#x1f393;作者简介&#xff1a;嵌入式领域优质创作者&#x1f310;个人主页&#xff1a;妄北y &#x1f4de;个人QQ&#xff1a;2061314755 &#x1f48c;个人邮箱&#xff1a;[mailto:2061314755qq.com] &#x1f4f1;个人微信&#xff1a;Vir2025WB…

Ant Design pro 6.0.0 搭建使用以及相关配置

一、背景 在选择一款比较合适的中台的情况下&#xff0c;挑选了有arco design、ant design pro、soybean、vue-pure-admin等中台系统&#xff0c;经过筛选就选择了ant design pro。之前使用过arco design 搭建通过组件库拼装过后台管理界面&#xff0c;官方文档也比较全&#…

2024GDCPC广东省赛记录

比赛流程体验&#xff0c;依托&#xff0c;开赛几分钟了&#xff0c;选手还卡在门外无法入场&#xff0c;也没给延时&#xff0c;说好的桌上会发三支笔&#xff0c;于是我们就没准备&#xff0c;要了三次笔&#xff0c;终于在一小时后拿到了&#x1f605; 比赛题目体验&#xf…

Java基础22(JSON解析 注解)

目录 一、JSON解析 1. JSON语法 2. JSON的用途 3. Java解析JSON 4. 使用Fastjson 4.1 Fastjson 的优点 4.2 Fastjson 导包 4.3 Fastjson的主要对象 4.4 常用方法 将Java对象 "序列化"&#xff08;转换&#xff09; 为JSON字符串&#xff1a; 将JSON字符串…

YOLOv5改进策略:Focaler-IoU损失函数改进

文章目录 1、前言2、摘要3、Focaler-IoU&#xff1a;4、代码实现5、目标检测系列文章 1、前言 ​ 目标检测是计算机视觉的基本任务之一&#xff0c;旨在识别图像中的目标并定位其位置。目标检测算法可分为基于锚点和无锚点的方法。基于锚点的方法包括Faster R-CNN、YOLO系列、…

详细分析Element Plus中的ElMessageBox弹窗用法(附Demo及模版)

目录 前言1. 基本知识2. Demo3. 实战4. 模版 前言 由于需要在登录时&#xff0c;附上一些用户说明书的弹窗 对于ElMessageBox的基本知识详细了解 可通过官网了解基本的语法知识ElMessageBox官网基本知识 1. 基本知识 Element Plus 是一个基于 Vue 3 的组件库&#xff0c;其中…

20240523每日运维--------聊聊docker简介(一)

dotCloud 说Docker&#xff0c;必不可免不得不说dotCloud&#xff0c;Docker本来只是dotCloud公司的内部项目&#xff0c;其公司创始人 Solomon Hykes 发了一个内部项目&#xff0c;而这个项目就是Docker&#xff0c;自从2013年docker开源以后&#xff0c;在世界范围引起相当轰…

对于高速信号完整性,一块聊聊啊(12)

常见的无源电子器件 电子系统中的无源器件可以按照所担当的电路功能分为电路类器件、连接类器件。 A、电路类器件&#xff1a; &#xff08;1&#xff09;二极管&#xff08;diode&#xff09; &#xff08;2&#xff09;电阻器&#xff08;resistor&#xff09; &#xf…

浅谈对称加密非对称加密

对称加密&#xff1a;加密和解密使用的密钥是同一个 常见算法&#xff1a;DES、3DES、Blowfish、IDEA、RC4、RC5、RC6 和 AES非对称加密&#xff1a;需要两个密钥&#xff0c;一个公开密钥、一个私有密钥 常见算法&#xff1a;RSA、ECC&#xff08;移动设备用&#xff09;、Dif…

归并排序算法(经典、常见)

今天我们不刷力扣了&#xff0c;我们来复习&#xff08;手撕&#xff09;一下数据结构中的八大排序算法之一&#xff0c;归并排序 基本概念&#xff1a; 归并排序&#xff08;Merge sort&#xff09;是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法&am…

【网络技术】【Kali Linux】Wireshark嗅探(十五)SSDP(简单服务发现协议)报文捕获及分析

往期 Kali Linux 上的 Wireshark 嗅探实验见博客&#xff1a; 【网络技术】【Kali Linux】Wireshark嗅探&#xff08;一&#xff09;ping 和 ICMP 【网络技术】【Kali Linux】Wireshark嗅探&#xff08;二&#xff09;TCP 协议 【网络技术】【Kali Linux】Wireshark嗅探&…

与MySQL DDL 对比分析OceanBase DDL的实现

本文将简要介绍OceanBase的DDL实现方式&#xff0c;并通过与MySQL DDL实现的对比&#xff0c;帮助大家更加容易理解。 MySQL DDL 的算法 MySQL 的DDL实现算法主要有 copy、inplace和instant。 copy copy算法的实现相对简单&#xff0c;MySQL首先会创建一个临时表&#xff0…

C++:STL

STL 文章目录 STLSTL 绪论迭代器&#xff08;iterators&#xff09;容器&#xff08;Containers&#xff09;vectorset,multisetmap,multimapstackqueuedequepriority_queuebitset 算法&#xff08;Algorithms&#xff09;sort,count,find,lower_bound,upper_bound,binary_sear…

(2024,attention,可并行计算的 RNN,并行前缀扫描)将注意力当作 RNN

Attention as an RNN 公众号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方法 3.1 注意力作为一种&#xff08;多对一的&#xff09;RNN 3.2 注意力作为&#xff08;多对多&…

多语言印度红绿灯系统源码带三级分销代理功能

前端为2套UI&#xff0c;一套是html写的&#xff0c;一套是编译后的前端 后台功能很完善&#xff0c;带预设、首充返佣、三级分销机制、代理功能。 东西很简单&#xff0c;首页就是红绿灯的下注页面&#xff0c;玩法虽然单一&#xff0c;好在不残缺可以正常跑。

Putty: 随心御剑——远程启动服务工具plink

一、引言:如何远程控制 也许你会有这样的场景,交互程序(以下简称UI程序)跑在windows端,而控制程序跑在Linux上。我们想要通过windows端 UI程序来启动Linux下面的服务,来一场酣畅淋漓的御剑飞行咋办,难道要自己十年磨一剑,在Linux下编写一个受控服务程序么.计算机科技发…