HOW - React Router v6.x Feature 实践(react-router-dom)
目录
- 基本特性
- ranked routes matching
- active links
- NavLink
- useMatch
- relative links
- 1. 相对路径的使用
- 2. 嵌套路由的增强行为
- 3. 优势和注意事项
- 4. . 和 ..
- 5. 总结
- data loading
- loading or changing data and redirect
- pending navigation ui
- skeleton ui with suspense
- data mutations with `<Route action>`
- busy indicators with route actions
- data fetchers
基本特性
- client side routing
- nested routes
- dynamic segments
比较好理解,这里不赘述。
ranked routes matching
https://reactrouter.com/en/main/start/overview#ranked-route-matching
When matching URLs to routes, React Router will rank the routes according to the number of segments, static segments, dynamic segments, splats, etc. and pick the most specific match.
这句话描述了 React Router 在匹配 URL 和路由时的策略,即根据路由的具体性来优先选择最合适的匹配项。让我们逐步解析这句话的含义:
-
URL 和路由的匹配:
- 当用户访问某个 URL 时,React Router 需要确定哪个路由规则最适合处理该 URL。例如,对于 URL
/users/123
,React Router 需要决定是匹配/users/:id
还是其他定义的路由。
- 当用户访问某个 URL 时,React Router 需要确定哪个路由规则最适合处理该 URL。例如,对于 URL
-
路由匹配的考量因素:优先级由高到低
-
路由的段数(Segments):URL 和路由可以分成多个段(segments),例如
/users/123
有两个段,/users/:id
也有两个段。React Router 会比较 URL 和每个路由的段数,越多的段数一般意味着路由更具体。 -
静态段(Static Segments):静态段是指在路由中直接指定的固定路径,例如
/users
是一个静态段。React Router 会考虑静态段的数量来确定路由的具体性。 -
动态段(Dynamic Segments):动态段是指在路由中使用参数化路径,例如
/users/:id
中的:id
是一个动态段。动态段的存在可能使得路由更灵活但也更具体。 -
通配符(Splat):通配符(如
*
)表示匹配多个路径段,通常用于处理不确定数量的路径部分。
-
-
最具体的匹配:
- React Router 会通过比较以上因素来确定哪个路由定义是最具体的匹配。具体的路由定义意味着它能够最准确地匹配当前的 URL,而不会与其他可能的路由定义冲突。
-
示例:
<Route path="/teams/:teamId" />
<Route path="/teams/new" />
对于 http://example.com/teams/new.
会优先匹配第二个 Route。因为静态段数为 2,更具体。
理解 React Router 的路由匹配策略,特别是根据路由的具体性来优先选择最合适的匹配项,有助于开发者更有效地设计和管理复杂的路由结构。通过正确的路由定义和优先级排序,可以确保应用程序在导航和页面渲染时行为符合预期,并能够灵活地应对各种场景和URL路径。
active links
NavLink
https://reactrouter.com/en/main/components/nav-link
<NavLinkstyle={({ isActive, isPending }) => {return {color: isActive ? "red" : "inherit",};}}className={({ isActive, isPending }) => {return isActive ? "active" : isPending ? "pending" : "";}}
/>
useMatch
https://reactrouter.com/en/main/hooks/use-match
function SomeComp() {const match = useMatch("/messages");return <li className={Boolean(match) ? "active" : ""} />;
}
relative links
理解 React Router 中 <Link>
和 <NavLink>
组件相对路径的使用需要考虑它们与 HTML 中 <a>
标签的行为差异,尤其是在嵌套路由场景下的增强行为。
1. 相对路径的使用
-
HTML
<a>
标签:在 HTML 中,使用<a>
标签时,相对路径通常相对于当前页面的完整 URL。这意味着,相对路径会根据当前页面的路径来构建最终的目标 URL。<a href="about">About</a>
- 如果当前 URL 是
http://example.com/home
,那么点击上述链接将导航到http://example.com/about
。
- 如果当前 URL 是
-
React Router 中的
<Link>
和<NavLink>
:在 React Router 中,<Link>
和<NavLink>
组件可以接受相对路径,但它们的行为略有不同。import { Link, NavLink } from 'react-router-dom';<Link to="about">About</Link> <NavLink to="about">About</NavLink>
- 这里的
to="about"
是相对路径,相对于当前路由的路径来构建目标 URL。例如,如果当前路由是/home
,那么这两个链接将会导航到/home/about
。
- 这里的
2. 嵌套路由的增强行为
-
嵌套路由:当应用程序中存在嵌套路由时,React Router 的
<Link>
和<NavLink>
组件表现出更智能的行为,确保相对路径的正确解析。<Route path="/home"><Link to="about">About</Link><NavLink to="about">About</NavLink> </Route>
- 在上述例子中,假设当前路由是
/home
,那么<Link>
和<NavLink>
组件会基于当前路由的路径/home
构建相对路径,导航到/home/about
。
- 在上述例子中,假设当前路由是
3. 优势和注意事项
-
灵活性和便利性:相对路径的使用使得在应用中链接管理更加灵活和简单,尤其是在处理嵌套路由时。
-
注意路径解析:确保理解相对路径在不同嵌套层级下的解析规则。React Router 的行为通常是基于当前活动的路由来解析相对路径,而不是简单地相对于根路径。
4. . 和 …
<Route path="/home"><Link to=".">About</Link><NavLink to=".">About</NavLink>
</Route>
- 在上述例子中,假设当前路由是
/home
,那么<Link>
和<NavLink>
组件会基于当前路由的路径/home
构建相对路径,导航到/home
。
<Route path="home" element={<Home />}><Route path="project/:projectId" element={<Project />}><Route path=":taskId" element={<Task />} /></Route>
</Route>
Project 中会渲染:
<Link to="abc"><Link to="."><Link to=".."></Link><Link to=".." relative="path">
- 在上述例子中,假设当前路由是
/home/project/123
,那么<Link>
会基于当前路由的路径构建相对路径,分别导航到/home/project/123/abc
、/home/project/abc
、/home
、/home/project
。
注意后面两个的差异:
By default, the … in relative links traverse the route hierarchy, not the URL segments. Adding relative=“path” in the next example allows you to traverse the path segments instead.
5. 总结
理解 React Router 中 <Link>
和 <NavLink>
组件相对路径的行为,特别是在嵌套路由情况下的增强行为,有助于开发者更有效地管理和导航应用程序中的链接。相对路径的使用使得在不同层级和场景下的导航操作更加灵活和便捷,但需要注意理解和控制路径的解析和构建规则。
data loading
https://reactrouter.com/en/main/start/overview#data-loading
Combined with nested routes, all of the data for multiple layouts at a specific URL can be loaded in parallel.
<Routepath="/"loader={async ({ request }) => {// loaders can be async functionsconst res = await fetch("/api/user.json", {signal: request.signal,});const user = await res.json();return user;}}element={<Root />}
><Routepath=":teamId"// loaders understand Fetch Responses and will automatically// unwrap the res.json(), so you can simply return a fetchloader={({ params }) => {return fetch(`/api/teams/${params.teamId}`);}}element={<Team />}><Routepath=":gameId"loader={({ params }) => {// of course you can use any data storereturn fakeSdk.getTeam(params.gameId);}}element={<Game />}/></Route>
</Route>
Data is made available to your components through useLoaderData.
function Root() {const user = useLoaderData();// data from <Route path="/">
}function Team() {const team = useLoaderData();// data from <Route path=":teamId">
}function Game() {const game = useLoaderData();// data from <Route path=":gameId">
}
When the user visits or clicks links to https://example.com/real-salt-lake/45face3, all three route loaders will be called and loaded in parallel, before the UI for that URL renders.
loading or changing data and redirect
https://reactrouter.com/en/main/route/loader#throwing-in-loaders
<Routepath="dashboard"loader={async () => {const user = await fake.getUser();if (!user) {// if you know you can't render the route, you can// throw a redirect to stop executing code here,// sending the user to a new routethrow redirect("/login");}// otherwise continueconst stats = await fake.getDashboardStats();return { user, stats };}}
/>
pending navigation ui
https://reactrouter.com/en/main/start/overview#pending-navigation-ui
When users navigate around the app, the data for the next page is loaded before the page is rendered. It’s important to provide user feedback during this time so the app doesn’t feel like it’s unresponsive.
function Root() {const navigation = useNavigation();return (<div>{navigation.state === "loading" && <GlobalSpinner />}<FakeSidebar /><Outlet /><FakeFooter /></div>);
}
skeleton ui with suspense
https://reactrouter.com/en/main/start/overview#skeleton-ui-with-suspense
Instead of waiting for the data for the next page, you can defer data so the UI flips over to the next screen with placeholder UI immediately while the data loads.
defer enables suspense for the un-awaited promises
<Routepath="issue/:issueId"element={<Issue />}loader={async ({ params }) => {// these are promises, but *not* awaitedconst comments = fake.getIssueComments(params.issueId);const history = fake.getIssueHistory(params.issueId);// the issue, however, *is* awaitedconst issue = await fake.getIssue(params.issueId);// defer enables suspense for the un-awaited promisesreturn defer({ issue, comments, history });}}
/>;function Issue() {const { issue, history, comments } = useLoaderData();return (<div><IssueDescription issue={issue} />{/* Suspense provides the placeholder fallback */}<Suspense fallback={<IssueHistorySkeleton />}>{/* Await manages the deferred data (promise) */}<Await resolve={history}>{/* this calls back when the data is resolved */}{(resolvedHistory) => (<IssueHistory history={resolvedHistory} />)}</Await></Suspense><Suspense fallback={<IssueCommentsSkeleton />}><Await resolve={comments}>{/* ... or you can use hooks to access the data */}<IssueComments /></Await></Suspense></div>);
}function IssueComments() {const comments = useAsyncValue();return <div>{/* ... */}</div>;
}
涉及如下 API 结合使用:
- defer
- Await
- useAsyncValue
data mutations with <Route action>
https://reactrouter.com/en/main/start/overview#data-mutations
HTML forms are navigation events, just like links. React Router supports HTML form workflows with client side routing.
When a form is submitted, the normal browser navigation event is prevented and a Request, with a body containing the FormData of the submission, is created. This request is sent to the <Route action>
that matches the form’s <Form action>
.
Form elements’s name prop are submitted to the action:
<Form action="/project/new"><label>Project title<br /><input type="text" name="title" /></label><label>Target Finish Date<br /><input type="date" name="due" /></label>
</Form>
<Routepath="project/new"action={async ({ request }) => {const formData = await request.formData();const newProject = await createProject({title: formData.get("title"),due: formData.get("due"),});return redirect(`/projects/${newProject.id}`);}}
/>
在 HTML 中,<form>
元素的 action
属性定义了当用户提交表单时将数据发送到的服务器端的 URL。
具体来说:
-
action
属性的作用:- 当用户提交表单时,浏览器会将表单中的数据发送到指定的 URL。
- 这个 URL 可以是相对路径或绝对路径。
- 如果
action
属性未指定,表单会被提交到当前页面的 URL(即自身)。
-
使用示例:
<form action="/project/new" method="post"><!-- 表单内容 --><input type="text" name="project_name" /><button type="submit">提交</button> </form>
- 在这个例子中,
action
属性的值是"/project/new"
。当用户点击提交按钮时,表单数据将被发送到当前服务器的/project/new
路径。
- 在这个例子中,
-
重要说明:
- 如果
action
属性指向一个相对路径,表单数据会被提交到当前页面的基础 URL 加上action
的值。 - 如果
action
属性是绝对路径(例如http://example.com/project/new
),数据将被发送到指定的绝对路径。
- 如果
-
HTTP 方法 (
method
属性):- 另一个与
action
相关的重要属性是method
,它指定了使用何种 HTTP 方法将表单数据发送到服务器。 - 常见的方法是
GET
和POST
。GET
方法将数据附加到 URL 上(可见),而POST
方法将数据包含在请求体中(不可见)。
- 另一个与
总结来说,action
属性定义了表单数据提交的目标 URL。这对于将用户输入数据发送到后端处理或其他指定的处理程序非常重要。
busy indicators with route actions
https://reactrouter.com/en/main/start/overview#busy-indicators
When forms are being submitted to route actions, you have access to the navigation state to display busy indicators, disable fieldsets, etc.
function NewProjectForm() {const navigation = useNavigation();const busy = navigation.state === "submitting";return (<Form action="/project/new"><fieldset disabled={busy}><label>Project title<br /><input type="text" name="title" /></label><label>Target Finish Date<br /><input type="date" name="due" /></label></fieldset><button type="submit" disabled={busy}>{busy ? "Creating..." : "Create"}</button></Form>);
}
data fetchers
HTML Forms are the model for mutations but they have one major limitation: you can have only one at a time because a form submission is a navigation.
Most web apps need to allow for multiple mutations to be happening at the same time, like a list of records where each can be independently deleted, marked complete, liked, etc.
Fetchers allow you to interact with the route actions and loaders without causing a navigation in the browser, but still getting all the conventional benefits like error handling, revalidation, interruption handling, and race condition handling.
Imagine a list of tasks:
function Tasks() {const tasks = useLoaderData();return tasks.map((task) => (<div><p>{task.name}</p><ToggleCompleteButton task={task} /></div>));
}
Each task can be marked complete independently of the rest, with its own pending state and without causing a navigation with a fetcher:
function ToggleCompleteButton({ task }) {const fetcher = useFetcher();return (<fetcher.Form method="post" action="/toggle-complete"><fieldset disabled={fetcher.state !== "idle"}><input type="hidden" name="id" value={task.id} /><inputtype="hidden"name="status"value={task.complete ? "incomplete" : "complete"}/><button type="submit">{task.status === "complete"? "Mark Incomplete": "Mark Complete"}</button></fieldset></fetcher.Form>);
}
相关文章:

HOW - React Router v6.x Feature 实践(react-router-dom)
目录 基本特性ranked routes matchingactive linksNavLinkuseMatch relative links1. 相对路径的使用2. 嵌套路由的增强行为3. 优势和注意事项4. . 和 ..5. 总结 data loadingloading or changing data and redirectpending navigation uiskeleton ui with suspensedata mutati…...

`padding`、`border`、`width`、`height` 和 `display` 这些 CSS 属性的作用
盒模型中的属性 padding(内边距) padding 用于控制元素内容与边框之间的空间,可以为元素的每个边(上、右、下、左)分别设置内边距。内边距的单位可以是像素(px)、百分比(%…...

C++ QT 全局信号的实现
每次做全局信号都需要重新建立文件,太麻烦了,记录一下,以后直接复制。 头文件 globalSignalEmitter.h #pragma once //#ifndef GLOBALSIGNALEITTER_H //#define GLOBALSIGNALEITTER_H#include <QObject>class GlobalSignalEmitter : …...

十款绚丽的前端 CSS 菜单导航动画
CSS汉堡菜单是一种非常流行的PC端和移动端web菜单风格,特别是移动端,这种风格的菜单应用更为广泛。这款菜单便非常适合在手机App上使用,它的特点是当顶部菜单弹出时,页面内容将会配合菜单出现适当的联动,让整个页面变得…...

debain系统使用日志
账号 vboxuser changeme ssh远程登录vbox虚拟机 https://www.cnblogs.com/BuzzWeek/p/17557981.html Terminal su - root changeme sudo apt-get update sudo apt-get -y install openssh-server #启动sshd systemctl status sshd 设置允许ssh登录vbox虚拟机 参考…...

【Word】快速对齐目录
目录标题 1. 全选要操作的内容 → 右键 → 段落2. 选则制表位3. 配置制表符4. Tab键即可 1. 全选要操作的内容 → 右键 → 段落 2. 选则制表位 3. 配置制表符 4. Tab键即可...

MATLAB基础应用精讲-【数模应用】 岭回归(Ridge)(附MATLAB、python和R语言代码实现)
目录 前言 算法原理 数学模型 Ridge 回归的估计量 Ridge 回归与标准多元线性回归的比较 3. Ridge 参数的选择 算法步骤 SPSSPRO 1、作用 2、输入输出描述 3、案例示例 4、案例数据 5、案例操作 6、输出结果分析 7、注意事项 8、模型理论 SPSSAU 岭回归分析案…...

推荐6个开源博客项目源码,你会选哪个呢
搭建个人博客系统时,可以选择多种开源平台,以下是一些受欢迎的开源博客系统及其特点: 1. Plumemo Plumemo 是一个轻量、易用、前后端分离的博客系统,为了解除开发人员对后端的束缚,真正做到的一个面向接口开发的博客…...

OCR text detect
主干网络 VoVNet:实时目标检测的新backbone网络_vovnet pytorch-CSDN博客 DenseNet: arxiv.org/pdf/1608.06993 密集连接: DenseNet 的核心思想是将网络中的每一层与其前面的所有层直接连接。对于一个 L 层的网络,DenseNet 具有…...

【MySQL】MySQL连接池原理与简易网站数据流动是如何进行
MySQL连接池原理与简易网站数据流动是如何进行 1.MySQL连接池原理2.简易网站数据流动是如何进行 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃ὠ…...

学数据结构学的很慢,毫无头绪怎么办 ?
这个情况比较正常诶,不用有太大的心理压力。 然后程序设计那个没有学过,而数据结构的前置课程之一就是程序设计,比如栈/队列/树,这些数据结构都要基于代码实现的。我估计是因为你之前缺少学习程序设计的经验,所以学起…...

VSCode常用快捷键和功能
格式化代码: ShiftAltF JS中自动输入console.log()的方法: 先在vscode中,找到文件 > 首选项 > 配置用户代码片段,在弹出的下拉框处方输入javascript.json,复制下面的代码,覆盖原来的代码࿰…...

上海市计算机学会竞赛平台2023年2月月赛丙组平分数字(一)
题目描述 给定 𝑛n 个整数:𝑎1,𝑎2,⋯ ,𝑎𝑛a1,a2,⋯,an,请判定能否将它们分成两个部分(不得丢弃任何数字),每部分的数字之和一样大。 输入格式 第…...

Qwen1.5-1.8b部署
仿照ChatGLM3部署,参考了Qwen模型的文档,模型地址https://modelscope.cn/models/qwen/Qwen1.5-1.8B-Chat/summary http接口 服务端代码api.py from fastapi import FastAPI, Request from transformers import AutoTokenizer, AutoModelForCausalLM, …...

关于7月1号centos官方停止维护7系列版本导致centos7+版本的机器yum等命令无法使用的解决教程
更换yum源两种方式 第一种 在还能使用yum等命令的情况是执行下面的命令 注意:阿里云和腾讯云二选一即可 一丶 yum源 腾讯云: wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.cloud.tencent.com/repo/centos7_base.repo curl -o /etc/yum.…...

2024人工智能大会_强化学习论坛相关记录
求解大规模数学优化问题 规划也称为优化 四要素:数据、变量、目标、约束 将一个简单的数学规划问题项gpt进行提问,GPT给了一个近似解,但不是确切的解。 大模型的训练本身就是一个优化问题。 大模型是如何训练的?大模型训练通常使…...

Android SurfaceFlinger——创建EGLContext(二十五)
前面文章我们获取了 EGL 的最优配置,创建了 EGLSurface 并与 Surface 进行了关联,然后还需要获取 OpenGL ES 的上下文 Context,这也是 EGL 控制接口的三要素(Displays、Contexts 和 Surfaces)之一。 1)getInternalDisplayToken:获取显示屏的 SurfaceControl 令牌(Token…...

python 10个自动化脚本
目录 🌟 引言 📚 理论基础 🛠️ 使用场景与代码示例 场景一:批量重命名文件 场景二:自动下载网页内容 场景三:数据清洗 场景四:定时执行任务 场景五:自动化邮件发送 场景六…...

填报高考志愿,怎样正确地选择大学专业?
大学专业的选择,会关系到未来几年甚至一辈子的发展方向。这也是为什么很多人结束高考之后就开始愁眉苦脸,因为他们不知道应该如何选择大学专业,生怕一个错误的决定会影响自己一生。 毋庸置疑,在面对这种选择的时候,我…...

Java 使用sql查询mongodb
在现代应用开发中,关系型数据库和NoSQL数据库各有千秋。MongoDB作为一种流行的NoSQL数据库,以其灵活的文档模型和强大的扩展能力,受到广泛欢迎。然而,有时开发者可能更熟悉SQL查询语法,或者需要在现有系统中复用SQL查询…...

WIN32核心编程 - 线程操作(二) 同步互斥
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 竞态条件 CriticalSection Mutex CriticalSection & Mutex Semaphore Event 竞态条件 多线程环境下,当多个线程同时访问或者修改同一个数据时,最终结果为线程执…...

web自动化(六)unittest 四大组件实战(京东登录搜索加入购物车)
Unittest框架 Unittest框架:框架测试模块测试管理模块测试统计模块,python的内置模块 import unittest Unittest框架四大组件: 1、TestCase 测试用例 2.TestFixture 测试用例夹具 测试用例需要执行的前置和后置 3.TestSuite 测试套件 把需要执行的测试用例汇总在一…...

鸿蒙语言基础类库:【@ohos.process (获取进程相关的信息)】
获取进程相关的信息 说明: 本模块首批接口从API version 7开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。开发前请熟悉鸿蒙开发指导文档:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。…...

华为笔试题
文章目录 1、数的分解2、字符串判断子串 1、数的分解 给定一个正整数n,如果能够分解为m(m > 1)个连续正整数之和, 请输出所有分解中,m最小的分解。 如果给定整数无法分解为连续正整数,则输出字符串"N"。 输入描述&a…...

【MySQL基础篇】函数及约束
1、函数 函数是指一段可以直接被另一段程序程序调用的程序或代码。 函数 - 字符串函数 MySQL中内置了很多字符串函数,常用的几个如下: 函数功能CONCAT(S1,S2,...,Sn)字符串拼接,将S1,S2,...,Sn拼接成一个字符串LOWER(str)将字符串str全部…...

YOLOv9报错:AttributeError: ‘list‘ object has no attribute ‘view‘
报错信息如下: red_distri, pred_scores torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( AttributeError: ‘list’ object has no attribute ‘view’ 解决方法: 去yolov9/utils/loss_tal.py把167行代码更改&#…...

Bert入门-使用BERT(transformers库)对推特灾难文本二分类
Kaggle入门竞赛-对推特灾难文本二分类 这个是二月份学习的,最近整理资料所以上传到博客备份一下 数据在这里:https://www.kaggle.com/competitions/nlp-getting-started/data github(jupyter notebook):https://gith…...

【DFS(深度优先搜索)详解】看这一篇就够啦
【DFS详解】看这一篇就够啦 🍃1. 算法思想🍃2. 三种枚举方式🍃2.1 指数型枚举🍃2.2 排列型枚举🍃2.3 组合型枚举 🍃3. 剪枝优化🍃4. 图的搜索🍃5. 来几道题试试手🍃5.1 选…...

java-spring boot光速入门教程(超详细!!)
目录 一、引言 1.1 初始化配置 1.2 整合第三方框架 1.3 后期维护 1.4 部署工程 1.5 敏捷式开发 二、SpringBoot介绍 spring boot 2.1 搭建一个spring boot工程 2.2 使用idea创建项目 2.3 在线创建姿势 2.4 项目的目录结构 2.5 项目的运行方式 2.6 yml文件格式 2…...

一、Prometheus和Grafana搭建
一、服务端Prometheus二进制安装 https://prometheus.io/下载过慢可使用迅雷下载 tar -zxvf prometheus-2.53.0.linux-amd64.tar.gz启动 ./prometheus --config.fileprometheus.yml将其配置为系统服务: vim /usr/lib/systemd/system/prometheus.service[Unit] D…...