一文学会使用React-Router v6

文章目录

    • 基本格式
      • createBrowserRouter
        • Type Declaration
          • routes
          • basename
          • future and window ... 省略
      • <RouterProvider>
        • fall上述文本提到 `createBrowserRouter` 函数的一个特性:在非服务器端渲染应用程序时,当它挂载时会初始化所有匹配的路由加载器。在此期间,你可以提供 `fallbackElement`,以向用户显示应用程序正在加载的指示。
        • future ...
      • Components
        • <Await>

以下内容来自官方文档 https://reactrouter.com/en/main

基本格式

import * as React from "react";
import { createRoot } from "react-dom/client";
import {createBrowserRouter,RouterProvider,Route,Link,
} from "react-router-dom";const router = createBrowserRouter([{path: "/",element: (<div><h1>Hello World</h1><Link to="about">About Us</Link></div>),},{path: "about",element: <div>About</div>,},
]);createRoot(document.getElementById("root")).render(<RouterProvider router={router} />
);

createBrowserRouter

import * as React from "react";
import * as ReactDOM from "react-dom";
import {createBrowserRouter,RouterProvider,
} from "react-router-dom";import Root, { rootLoader } from "./routes/root";
import Team, { teamLoader } from "./routes/team";const router = createBrowserRouter([{path: "/",element: <Root />,loader: rootLoader,children: [{path: "team",element: <Team />,loader: teamLoader,},],},
]);ReactDOM.createRoot(document.getElementById("root")).render(<RouterProvider router={router} />
);

Type Declaration
function createBrowserRouter(routes: RouteObject[],opts?: {basename?: string;future?: FutureConfig;hydrationData?: HydrationState;window?: Window;}
): RemixRouter;

routes

An array of Route objects with nested routes on the children property.

createBrowserRouter([{path: "/",element: <Root />,loader: rootLoader,children: [{path: "events/:id",element: <Event />,loader: eventLoader,},],},
]);

Route定义为:

const router = createBrowserRouter([{// it renders this elementelement: <Team />,// when the URL matches this segmentpath: "teams/:teamId",// with this data loaded before renderingloader: async ({ request, params }) => {return fetch(`/fake/api/teams/${params.teamId}.json`,{ signal: request.signal });},// performing this mutation when data is submitted to itaction: async ({ request }) => {return updateFakeTeam(await request.formData());},// and renders this element in case something went wrongerrorElement: <ErrorBoundary />,},
]);

RouteObject对象的声明为:

interface RouteObject {path?: string;index?: boolean;children?: React.ReactNode;caseSensitive?: boolean;id?: string;loader?: LoaderFunction;action?: ActionFunction;element?: React.ReactNode | null;Component?: React.ComponentType | null;errorElement?: React.ReactNode | null;ErrorBoundary?: React.ComponentType | null;handle?: RouteObject["handle"];shouldRevalidate?: ShouldRevalidateFunction;lazy?: LazyRouteFunction<RouteObject>;
}

对于Path:
动态路由参数, 可以在loader, action中通过params直接点出 或者使用useParams()钩子来获取该参数

<Route// this path will match URLs like// - /teams/hotspur// - /teams/realpath="/teams/:teamId"// the matching param will be available to the loaderloader={({ params }) => {console.log(params.teamId); // "hotspur"}}// and the actionaction={({ params }) => {}}element={<Team />}
/>;// and the element through `useParams`
function Team() {let params = useParams();console.log(params.teamId); // "hotspur"
}

你可以定义多个动态参数 都可以通过 . 运算符获取到

<Route path="/c/:categoryId/p/:productId" />;
// both will be available
params.categoryId;
params.productId;

可选参数 通过在后面加上 ?

<Route// this path will match URLs like// - /categories// - /en/categories// - /fr/categoriespath="/:lang?/categories"// the matching param might be available to the loaderloader={({ params }) => {console.log(params["lang"]); // "en"}}// and the actionaction={({ params }) => {}}element={<Categories />}
/>;// and the element through `useParams`
function Categories() {let params = useParams();console.log(params.lang);
}

当然可以同时用动态参数和可选参数

模糊匹配所有的 * 参数

<Route// this path will match URLs like// - /files// - /files/one// - /files/one/two// - /files/one/two/threepath="/files/*"// the matching param will be available to the loaderloader={({ params }) => {console.log(params["*"]); // "one/two"}}// and the actionaction={({ params }) => {}}element={<Team />}
/>;// and the element through `useParams`
function Team() {let params = useParams();console.log(params["*"]); // "one/two"
}

布局路由

<Routeelement={<div><h1>Layout</h1><Outlet /></div>}
><Route path="/" element={<h2>Home</h2>} /><Route path="/about" element={<h2>About</h2>} />
</Route>

组件留出子路由要渲染的位置,仅此而已
index索引路由 url为父路径时显示的组件

<Route path="/teams" element={<Teams />}><Route index element={<TeamsIndex />} /><Route path=":teamId" element={<Team />} />
</Route>
  • 外层的<Route>有一个路径path为"/teams",并渲染了一个组件<Teams />
  • 在这个路由内部,有另一个带有index属性的嵌套的<Route>。这意味着当路径匹配"/teams"时,组件<TeamsIndex />将被呈现到其父级路由的Outlet中(在这种情况下是<Teams />)。
  • 此外,还有另一个带有path=":teamId"的嵌套路由,表示当路径匹配"/teams/:teamId"时,将呈现组件<Team />

children: 嵌套路由
caseSensitive: 表示对路径中大小写敏感
Instructs the route to match case or not:

<Route caseSensitive path="/wEll-aCtuA11y" />
  • Will match “wEll-aCtuA11y”
  • Will not match “well-actua11y”

loader
每一个路由都能定义一个loader函数来为路由组件渲染之前提供数据

createBrowserRouter([{element: <Teams />,path: "teams",loader: async () => {return fakeDb.from("teams").select("*");},children: [{element: <Team />,path: ":teamId",loader: async ({ params }) => {return fetch(`/api/teams/${params.teamId}.json`);},},],},
]);

通过 调用loader函数获得的数据可以通过 useLoaderData钩子拿到
useLoaderData: This hook provides the value returned from your route loader.

import {createBrowserRouter,RouterProvider,useLoaderData,
} from "react-router-dom";function loader() {return fetchFakeAlbums();
}export function Albums() {const albums = useLoaderData();// ...
}const router = createBrowserRouter([{path: "/",loader: loader,element: <Albums />,},
]);ReactDOM.createRoot(el).render(<RouterProvider router={router} />
);

在调用路由操作之后,数据将自动重新验证,并从加载器返回最新的结果。
请注意,useLoaderData 不会启动抓取。它只是读取 React Router 在内部管理的抓取结果,因此您不必担心在重新呈现的原因之外的情况下重新获取数据。
这也意味着在重新呈现之间返回的数据是稳定的,因此您可以安全地将其传递给 React hooks(如 useEffect)中的依赖数组。它只在再次调用加载器后(在执行操作或特定导航后)才会更改。在这些情况下,标识将更改(即使值没有更改)。
您可以在任何组件或任何自定义 hook 中使用此钩子,而不仅仅是在 Route 元素中。它将返回上下文中最近路由的数据。
params: 由url中解析的动态参数会放在params中并传递给loader函数

createBrowserRouter([{path: "/teams/:teamId",loader: ({ params }) => {return fakeGetTeam(params.teamId);},},
]);

request:

<ahref={props.to}onClick={(event) => {event.preventDefault();navigate(props.to);}}
/>

React router阻止浏览器将请求request发送给server, 而是转给了loader函数

function loader({ request }) {const url = new URL(request.url);const searchTerm = url.searchParams.get("q");return searchProducts(searchTerm);
}

返回 response
可以返回fetch()发送异步请求(ajax, axios)的结果,也可以自定义返回结果

// an HTTP/REST API
function loader({ request }) {return fetch("/api/teams.json", {signal: request.signal,});
}// or even a graphql endpoint
function loader({ request, params }) {return fetch("/_gql", {signal: request.signal,method: "post",body: JSON.stringify({query: gql`...`,params: params,}),});
}function loader({ request, params }) {const data = { some: "thing" };return new Response(JSON.stringify(data), {status: 200,headers: {"Content-Type": "application/json; utf-8",},});
}

react router会自动调用 response.json()

function SomeRoute() {const data = useLoaderData();// { some: "thing" }
}

在loader中抛出异常

function loader({ request, params }) {const res = await fetch(`/api/properties/${params.id}`);if (res.status === 404) {throw new Response("Not Found", { status: 404 });}return res.json();
}

会渲染路由中定义的 errorElement组件
action: 进行写操作的函数

<Routepath="/song/:songId/edit"element={<EditSong />}action={async ({ params, request }) => {let formData = await request.formData();return fakeUpdateSong(params.songId, formData);}}loader={({ params }) => {return fakeGetSong(params.songId);}}
/>

在应用发起一个非get请求时被调用 比如按钮点击

// forms
<Form method="post" action="/songs" />;
<fetcher.Form method="put" action="/songs/123/edit" />;// imperative submissions
let submit = useSubmit();
submit(data, {method: "delete",action: "/songs/123",
});
fetcher.submit(data, {method: "patch",action: "/songs/123/edit",
});

element / Component: 要渲染的组件
errorElement / ErrorBoundary: 异常时渲染的组件
当在loader, action函数执行或者组件渲染时抛出异常, 就不会渲染element组件, 而是用error path的组件 errorElement渲染, 该异常可以用 useRouteError获取
lazy :

let routes = createRoutesFromElements(<Route path="/" element={<Layout />}><Route path="a" lazy={() => import("./a")} /><Route path="b" lazy={() => import("./b")} /></Route>
);

basename

The basename of the app for situations where you can’t deploy to the root of the domain, but a sub directory.

createBrowserRouter(routes, {basename: "/app",
});

future and window … 省略

All data router objects are passed to this component to render your app and enable the rest of the data APIs

import {createBrowserRouter,RouterProvider,
} from "react-router-dom";const router = createBrowserRouter([{path: "/",element: <Root />,children: [{path: "dashboard",element: <Dashboard />,},{path: "about",element: <About />,},],},
]);ReactDOM.createRoot(document.getElementById("root")).render(<RouterProviderrouter={router}fallbackElement={<BigSpinner />}/>
);

fall上述文本提到 createBrowserRouter 函数的一个特性:在非服务器端渲染应用程序时,当它挂载时会初始化所有匹配的路由加载器。在此期间,你可以提供 fallbackElement,以向用户显示应用程序正在加载的指示。

这个特性的目的是在加载路由数据时,提供一个加载过程中的占位元素(fallback element),使用户在等待加载完成时能够看到一些界面反馈,而不是一片空白。
举例来说,你可以在 createBrowserRouter 中添加 fallbackElement 选项,像这样:

createBrowserRouter(routes, {fallbackElement: <div>Loading...</div>,
});

这样,当路由加载的过程中,页面将显示 “Loading…”,以告诉用户应用程序正在处理数据,避免用户在加载过程中感到不确定或无反馈。

future …

Components

import { Await, useLoaderData } from "react-router-dom";function Book() {const { book, reviews } = useLoaderData();return (<div><h1>{book.title}</h1><p>{book.description}</p><React.Suspense fallback={<ReviewsSkeleton />}><Awaitresolve={reviews}errorElement={<div>Could not load reviews 😬</div>}children={(resolvedReviews) => (<Reviews items={resolvedReviews} />)}/></React.Suspense></div>);
}

这段代码是一个使用 React Router 的 useLoaderDataAwait 组件的 React 组件。让我解释一下它的主要部分:

  1. useLoaderData 是 React Router 提供的一个 hook,用于获取路由加载器(loader)返回的数据。在这里,通过 useLoaderData 获取了 bookreviews
  2. return 中,首先渲染了 book 的标题和描述。
  3. 使用了 React 的 Suspense 组件,它接受 fallback 属性,指定在子组件加载过程中显示的占位元素。在这里,如果 reviews 尚未加载完成,将显示一个 ReviewsSkeleton 组件,用作加载占位符。
  4. 使用 Await 组件包装了 reviews 的加载。Await 组件接受 resolve 属性,指定需要等待的 Promise。如果 resolve Promise 处于 pending 状态,它会渲染 fallback 中的占位元素;如果 Promise 处于 resolved 状态,它会调用 children 函数,并将 resolved 的数据传递给它。
  5. children 函数中,渲染了一个 Reviews 组件,传递了从 reviews 获取的 resolved 数据。

总体来说,这段代码的目的是展示书籍的标题和描述,同时以异步方式加载书籍的评论。在加载评论的过程中,会显示一个加载中的占位符,确保用户在等待数据加载完成时能够看到一些界面反馈。如果加载评论失败,将显示一个错误提示。

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

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

相关文章

解决hbuilder使用android studio模拟器不能热更新

hbuilder使用android studio模拟器编&#xff0c;在编写代码时&#xff0c;不能热更新&#xff0c;总是需要重启虚拟机中的程序&#xff0c;hbuilderx的版本是3.1.22&#xff0c;android studio的版本是4.2.2 同时在hbuilderx中出现如下报错信息&#xff1a; 报错信息&#x…

HuggingFace学习笔记--AutoModel的使用

1--AutoModel的使用 官方文档 AutoModel 用于加载模型&#xff1b; 1-1--简单Demo 测试代码&#xff1a; from transformers import AutoTokenizer, AutoModelif __name__ "__main__":checkpoint "distilbert-base-uncased-finetuned-sst-2-english"t…

java进阶---多态

多态的概述 什么是多态 同一个对象,在不同时刻表现出来的不同形态 多态的前提 要有继承或实现关系要有方法的重写要有父类引用指向子类对象 多态的具体实现 对象的多态是多态的核心和重点 规则: 一个对象的编译类型与运行类型可以不一致编译类型在定义对象时,就确定了,…

三数之和问题

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例 1&…

【笔记 Pytorch 08】深度学习模板 (未完)

文章目录 一、声明二、工程结构三、文件内容main.pymodel.pydataset.pyutils.py 四、问题汇总 一、声明 非常感谢这些资料的作者&#xff1a; 【参考1】、【PyTorch速成教程 (by Sung Kim)】 二、工程结构 ├── main.py&#xff1a;实现训练 (train) 、验证(validation)和…

python pip安装第三方包时报错 error: Microsoft Visual C++ 14.0 or greater is required.

文章目录 1.问题2.原因3.解决办法 1.问题 pip install 的时候报错一大堆&#xff0c;其中有这么一段话 &#x1f447; error: Microsoft Visual C 14.0 or greater is required. Get it with "Microsoft C Build Tools": https://visualstudio.microsoft.com/visua…

rdf-file:读和写

<dependency><groupId>com.alipay.rdf.file</groupId><artifactId>rdf-file-core</artifactId><version>2.2.10</version> </dependency>一&#xff1a;读 一&#xff1a;写 写文件之正常写 协议布局模板 使用内置的布局文…

二分 模板

好久没更新博客了&#xff0c;之前一直在准备比赛&#xff0c;忙着学算法和写题&#xff0c;今天写了一道二分答案的题&#xff0c;发现之前那种二分写法有一丢丢的问题&#xff0c;导致有道题只能过97%的点。 emmm,还是把最经典的二分的板子写在这记录下&#xff08;这里参考…

python每日一题——8无重复字符的最长子串

题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串…

精进Beautiful Soup 小技巧(二)---处理多种页面结构

前言: 为了处理多种不同结构的页面&#xff0c;一个灵活的代码基础是至关重要的。一些针对性的技巧和方法&#xff0c;让你能够优雅地解决遇到的页面结构多元化的问题。 使用条件语句适配不同布局 当面对页面布局差异时&#xff0c;选择合适的条件语句至关重要。 认识布局类型…

正则表达式例题-PTA

PTA-7-55 判断指定字符串是否合法-CSDN博客 7-54 StringBuffer-拼接字符串 题目&#xff1a; 输入3个整数n、begin、end。 将从0到n-1的数字拼接为字符串str。如&#xff0c;n12&#xff0c;则拼接出来的字符串为&#xff1a;01234567891011 最后截取字符串str从begin到end(包…

【2023 年终盘点】今年用的最多的 10 款浏览器插件

分享顺哥今年用的最多的 10 款浏览器插件。 排名不分先后,涉及各个方面的应用。 大家有好用的插件也欢迎在评论区留言分享! 视频 YouTube:https://youtu.be/ZpTydUSBwCA 顺哥博客 浏览器扩展篇 注意: 1、以下介绍的均为在 Google Chrome 浏览器适用的小插件,部分插件…

2018年11月8日 Go生态洞察:参与2018年Go用户调查

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

一个通用的分页实体对象的思考

背景 用得非常多的一个分页实体对象 说明 只是一种抽象的思路, 可能不一定能够直接使用, 慎用. 只是一种抽象的思路, 可能不一定能够直接使用, 慎用. 只是一种抽象的思路, 可能不一定能够直接使用, 慎用. 分页实体 Data public class PageEntity<T> {/*** 分页后的结…

文件解析工具

前言 对Excel & CSV 文件解析 package com.wind.bird.Utils;import com.opencsv.CSVReader; import com.opencsv.CSVReaderBuilder; import org.apache.commons.validator.Var; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HS…

基于springboot学籍管理系统

一、设计目的 1. 复习、巩固Java语言的基础知识&#xff0c;进一步加深对Java语言的理解和掌握&#xff1b; 2. 课程设计为学生提供了一个既动手又动脑&#xff0c;独立实践的机会&#xff0c;将课本上的理论知识和实际有机的结合起来&#xff0c;锻炼学生的分析解决实际问题…

2016年五一杯数学建模B题能源总量控制下的城市工业企业协调发展问题解题全过程文档及程序

2016年五一杯数学建模 B题 能源总量控制下的城市工业企业协调发展问题 原题再现 能源是国民经济的重要物质基础,是工业企业发展的动力&#xff0c;但是过度的能源消耗&#xff0c;会破坏资源和环境&#xff0c;不利于经济的可持续发展。目前我国正处于经济转型的关键时期&…

关于 raw 图像的理解

1、问题背景 在图像调试过程&#xff0c;当发现一个问题时&#xff0c;很多时候都要通过 dump raw图像来分析&#xff0c;如果raw图像上有&#xff0c;那就排除了是 ISP的处理导致。 下一步就是排查 sensor 或者镜头&#xff0c;这样可以有效的帮我们定位问题所在。 但遇到过…

IDEA出现cannot download sources解决方案

IDEA出现cannot download sources解决方案 问题描述 当我想看第三方库的源码的注释时需要下载源码。 点击Dodnload Sources后可能会出现cannot download sources的问题。 解决方案 这时我们只需在根目录下打开Terminal后执行下面一行代码 mvn dependency:resolve -Dclassi…

王者荣耀Java

代码 package com.sxt;import javax.swing.*; import java.awt.*;public class Background extends GameObject {public Background(GameFrame gameFrame) {super(gameFrame);// TODO Auto-generated constructor stub}Image bg Toolkit.getDefaultToolkit().getImage("…