React-Router

186 阅读41分钟

公共Router技巧

两种路由写法

  1. 李立超的写法:使用Routes标签来实现路由的嵌套,这种写法很爽,但是长期来看就很垃圾。
  2. 黑马的写法:使用路由实例来管理嵌套路由。

介绍

安装

//网页端
npm install react-router-dom
//移动端
npm install react-router-native

李立超Route5和6

URL与组件进行映射

Route标签

path指定该标签的路径是什么,component指定它的子组件是什么。

Route标签,只要url的路径包含了path,即不管子路径是什么,都会显示该组件

Link和NavLink

使用Link标签可以起到和a标签一样的作用,Link标签会发生跳转,但是不会向服务器重新发送请求。

在React Router中,Link和NavLink标签的区别主要在于它们的行为和用途。

  1. Link:Link是React Router提供的一个组件,用于实现路由的跳转。当用户点击Link组件时,URL会更新,但页面不会重新加载。这意味着组件会被重新渲染,但不会进行完整的页面加载。使用Link时,可以通过to属性来描述需要定位的页面。
  2. NavLink:NavLink也是React Router提供的一个组件,它与Link类似,也可以实现路由的跳转。但是,NavLink在匹配上当前URL的时候,会给已经渲染的元素添加参数。这意味着,当用户点击NavLink组件时,除了更新URL外,还会向已经渲染的组件传递额外的参数。

总结来说,Link和NavLink的主要区别在于它们的行为和用途。Link主要用于简单的路由跳转,而NavLink在路由跳转的同时,还可以传递参数给已经渲染的组件。

在React Router中,NavLink组件是用于创建导航链接的组件之一,具有以下功能:

  1. 自动处理当前活动的路由:NavLink会自动检测当前活动的路由,并为其添加样式类名,以便通过CSS来区分活动路由。
  2. 提供活动样式自定义:通过activeClassName或activeStyle属性,可以自定义活动链接的样式。当链接处于活动状态时,这些样式将被应用到该链接上。
  3. 支持路由参数:NavLink可以接收路由参数,并将其传递给路由处理程序。这使得创建具有动态参数的路由变得简单和直观。
  4. 支持嵌套路由:通过使用NavLink组件,可以轻松创建嵌套路由,实现复杂的导航结构。
  5. 阻止默认行为:当点击NavLink时,默认情况下会触发页面跳转。但是,如果你想阻止这种行为并执行其他操作(例如打开模态框),你可以使用event.preventDefault()方法来阻止默认行为。
  6. 易于集成:NavLink组件可以很容易地与其他UI组件(如菜单、标签页等)集成,创建具有一致性和可用性的导航体验。

需要注意的是,尽管NavLink提供了许多有用的功能,但它仍然是一个React组件,因此在使用它时需要遵循React的最佳实践(例如避免在渲染方法中创建新的对象或函数)。同时,如果你只需要简单的路由导航而不需要额外的样式或行为,你也可以使用基本的组件。

BrowserRouter标签和HashRouter标签

component属性

向url传参,就是:参数名,可以通过打印props.match来查看传入的查看

在React Router中,必须要会match、history、location这三个属性,这三个属性里面的方法属性也是重中之重。

在React Router中,component属性可以传入类组件或函数组件。

在React Router中,使用标签直接写组件是component属性的简写形式。这意味着你可以直接在标签中指定要渲染的组件,而不需要使用render属性来返回组件。

例如,以下代码展示了使用component属性直接在标签中定义组件:

import React from 'react';  
import { BrowserRouter as Router, Route } from 'react-router-dom';  
  
const HomeComponent = () => {  
  return <h1>Home Component</h1>;  
};  
  
const AboutComponent = () => {  
  return <h1>About Component</h1>;  
};  
  
const App = () => {  
  return (  
    <Router>  
      <Route exact path="/" component={HomeComponent} />  
      <Route path="/about" component={AboutComponent} />  
    </Router>  
  );  
};

在上面的代码中,当用户访问根路径/时,将渲染HomeComponent组件。当用户访问/about路径时,将渲染AboutComponent组件。这是通过在标签中使用component属性直接指定要渲染的组件来实现的。

render属性

使用component属性时,不能写jsx代码,但使用render属性可以写jsx代码,但是不会将match、history、location这三个属性自动传入。必须要在render的回调函数中加个参数routePros,然后在标签里面将这个参数解构出来,就可以为组件带上这三个属性。

React Router中的render属性用于在匹配到某个路由时渲染一个组件,而不是直接将组件作为子元素插入到DOM中。render属性接受一个函数作为参数,该函数返回要渲染的组件。

以下是一个使用render属性的示例:

import React from 'react';  
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';  
  
const HomePage = () => {  
  return <h1>Home Page</h1>;  
};  
  
const AboutPage = () => {  
  return <h1>About Page</h1>;  
};  
  
const App = () => {  
  return (  
    <Router>  
      <Switch>  
        <Route exact path="/" render={(routePros) => <HomePage ...routePros />} />  
        <Route path="/about" render={() => <AboutPage />} />  
      </Switch>  
    </Router>  
  );  
};  
  
export default App;

在上面的示例中,当路由匹配到根路径/时,会渲染HomePage组件;当路由匹配到/about路径时,会渲染AboutPage组件。通过使用render属性,我们可以更灵活地控制组件的渲染方式。

children属性

下面这三个钩子很重要

URL传参

在React Router中,你可以通过路径参数和查询参数来传入多个参数。

  1. 路径参数:

路径参数是路由路径中的占位符,用于匹配URL中的特定部分。当匹配到路径参数时,它们将作为属性传递给组件。

例如,假设你有以下路由:

<Route path="/user/:userId" component={User} />

在这个例子中,:userId是一个路径参数。当用户访问/user/123时,userId的值将被解析为123,并作为属性传递给User组件。

在组件中,你可以通过props对象来访问这些参数。例如:

function User({ userId }) {  
  return <h1>User ID: {userId}</h1>;  
}

在React Router中,你可以使用组件的path属性来传入多个路径参数。路径参数使用冒号(:)作为占位符,可以接受任何字符串。

以下是一个示例,展示了如何传入多个路径参数:

import React from 'react';  
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';  
  
const HomePage = () => {  
  return <h1>Home Page</h1>;  
};  
  
const AboutPage = ({ match }) => {  
  const { params } = match;  
  const { userId, name } = params;  
  return <h1>About Page for User {userId} with Name {name}</h1>;  
};  
  
const App = () => {  
  return (  
    <Router>  
      <Switch>  
        <Route exact path="/" component={HomePage} />  
        <Route path="/about/:userId/:name" component={AboutPage} />  
      </Switch>  
    </Router>  
  );  
};  
  
export default App;

在上面的示例中,我们定义了一个AboutPage组件,它接受两个路径参数:userId和name。在组件中,我们使用:userId和:name作为路径参数的占位符。当用户访问/about/123/john时,AboutPage组件将接收到userId=123和name=john作为参数。

注意,在AboutPage组件中,我们通过match属性访问了路由匹配的结果,并从中提取了路径参数。你可以在函数组件中使用useRouteMatch钩子来获取路由匹配的结果。

  1. 查询参数:

查询参数是URL中的查询字符串部分,用于传递额外的参数。查询参数不会影响路由匹配,但可以在组件中通过location.search属性访问。

例如,假设你有以下路由:

<Route path="/search" component={Search} />

在这个例子中,你可以在URL中添加查询参数,如/search?keyword=react&page=1。在Search组件中,你可以通过location.search属性获取查询参数:

function Search() {  
  const query = new URLSearchParams(location.search);  
  const keyword = query.get('keyword');  
  const page = query.get('page');  
  // 处理查询参数...  
}

总结起来,你可以通过路径参数和查询参数在React Router中传入多个参数。路径参数是路由路径中的占位符,用于匹配URL中的特定部分,并作为属性传递给组件。查询参数是URL中的查询字符串部分,用于传递额外的参数,可以通过location.search属性在组件中访问。

Route标签的用法

useHistory方法

useHistory 是 React Router 库中的一个钩子(hook),它返回一个 history 对象,这个对象可以用于编程式导航。你可以使用 history 对象的 push 和 replace 方法来实现页面的跳转。

  • push 方法会向浏览器的历史记录中添加一个新的条目,类似于点击了一个链接。
  • replace 方法会替换当前的历史记录,而不是添加新的条目。

下面是一个使用 useHistory 的例子:

import { useHistory } from 'react-router-dom';  
  
function MyComponent() {  
  const history = useHistory();  
  
  const handleClick = () => {  
    history.push('/new-location'); // 导航到新的页面  
  };  
  
  return (  
    <button type="button" onClick={handleClick}>  
      Click Me!  
    </button>  
  );  
}

在这个例子中,当你点击按钮时,会调用 handleClick 函数,然后使用 history.push 方法导航到 /new-location。这样,你的应用程序就会显示新的页面。

路由嵌套

在React Router中,你可以使用嵌套路由来创建具有层次结构的路由。嵌套路由允许你在一个路由内部定义其他路由,从而实现更复杂的页面布局和导航。

要在React Router中实现嵌套路由,你可以使用Route组件和Switch组件。下面是一个简单的示例,演示了如何在React Router中进行嵌套路由:

import React from 'react';  
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';  
  
// 父级组件  
const ParentComponent = () => {  
  return (  
    <div>  
      <h1>Parent Component</h1>  
      <Route path="/nested" component={NestedComponent} />  
    </div>  
  );  
};  
  
// 嵌套子组件  
const NestedComponent = () => {  
  return (  
    <div>  
      <h2>Nested Component</h2>  
    </div>  
  );  
};  
  
const App = () => {  
  return (  
    <Router>  
      <Switch>  
        <Route exact path="/" component={HomeComponent} />  
        <Route path="/parent" component={ParentComponent} />  
      </Switch>  
    </Router>  
  );  
};

在上面的示例中,我们有一个ParentComponent作为父级组件,它内部使用了一个Route来定义嵌套路由。当访问/parent/nested路径时,会渲染NestedComponent作为嵌套子组件。注意,我们还在父级组件中使用了Switch来确保只渲染匹配的路由。

这只是一个简单的示例,你可以根据你的需求进行更复杂的嵌套路由配置。通过在父级组件中添加更多的Route和子组件,你可以构建出更复杂的页面结构和导航。

高级

Prompt标签

React Router中的Prompt组件用于在用户尝试导航到另一个页面时显示一个提示对话框。它可以帮助用户确认是否真的要离开当前页面,特别是在当前页面有未保存的数据时。

Prompt组件的message属性可以接受一个字符串或一个函数,用于定义提示对话框中的消息内容。当用户尝试导航到另一个页面时,会触发Prompt组件,显示指定的消息。

以下是一个使用Prompt组件的示例:

import { Prompt } from 'react-router-dom';  
  
function MyComponent() {  
  return (  
    <div>  
      <h1>My Page</h1>  
      <button onClick={() => window.history.push('/another-page')}>Go to Another Page</button>  
      <Prompt when={true} message="Are you sure you want to leave?" />  
    </div>  
  );  
}

在上面的示例中,当用户点击"Go to Another Page"按钮时,会触发Prompt组件,显示"Are you sure you want to leave?"的提示消息。如果用户确认要离开,则会导航到另一个页面。如果用户取消离开,则不会进行任何操作。

注意,在使用Prompt组件时,需要确保在组件中正确地处理路由导航和状态更新。

Redirect标签

React Router中的标签用于进行页面重定向。当某个路由匹配不成功时,或者根据某种条件需要进行重定向时,可以使用组件。

标签具有一些属性,用于定义重定向的目标URL和其他相关参数。其中最重要的属性是to,它指定了重定向的目标URL。

以下是一个简单的示例,演示了如何使用标签进行重定向:

import React from 'react';  
import { BrowserRouter as Router, Route, Redirect } from 'react-router-dom';  
  
const HomePage = () => {  
  return <h1>Home Page</h1>;  
};  
  
const AboutPage = () => {  
  return <h1>About Page</h1>;  
};  
  
const UsersPage = () => {  
  return <h1>Users Page</h1>;  
};  
  
const NotFoundPage = () => {  
  return (  
    <div>  
      <h1>404 - Page Not Found</h1>  
      <p>The requested page was not found.</p>  
      <Redirect to="/" />  
    </div>  
  );  
};  
  
const App = () => {  
  return (  
    <Router>  
      <Route exact path="/" component={HomePage} />  
      <Route path="/about" component={AboutPage} />  
      <Route path="/users" component={UsersPage} />  
      <Route path="*" component={NotFoundPage} />  
    </Router>  
  );  
};

在上面的示例中,当访问不存在的路径(例如/invalid)时,会渲染NotFoundPage组件。在该组件中,我们使用标签将用户重定向到首页(/)。通过设置to="/"属性,我们告诉React Router将用户导航到首页。

React Router中的标签用于重定向到新的URL。以下是标签的一些属性:

  1. to: 必需属性,用于指定重定向的目标URL。可以是任何有效的URL路径。
  2. push: 布尔属性,设为true时,重定向会将新条目推入历史记录,而不是替换当前条目。没办法用浏览器进行回退
  3. from: 字符串属性,用于指定要重定向的路径名。该属性用于覆盖to属性中的路径参数。当访问from属性的地址时就会跳转到to属性的地址。

这些属性可以帮助你控制重定向的行为和目标。请注意,实际上更像一个动作,只要这个组件被渲染就发生重定向动作。

React-Router6

新特性

React Router 6引入了一些新的语法和功能,以下是其中的一些:

  1. 使用 组件来包裹路由:在React Router 6中,必须使用 组件来包裹路由,而不是使用 组件。
  2. 使用 组件来定义路由:在React Router 6中,使用 组件来定义路由,这个组件相当于一个 if 语句,如果其路径与当前 URL 匹配,则呈现其对应的组件。
  3. 使用 组件实现导航的“高亮”效果:与 组件类似, 组件可以用于实现导航链接,并具有“高亮”效果。
  4. 使用 组件来渲染子路由:在React Router 6中,可以使用 组件来渲染子路由,而不是使用 组件。
  5. 使用 钩子来配置路由表:在React Router 6中,可以使用 钩子来获取路由表,然后根据路由表进行相应的操作。

总的来说,React Router 6的语法更加简洁明了,更加易于理解和使用。同时,React Router 6还新增了一些功能和钩子,使得开发人员可以更加方便地实现路由功能。

Routes标签

Routes是从上到下匹配路由,只要有一个匹配上了就不会再匹配了。Switch标签是可有可无的,但是在v6版本中,Routes标签就必须有。

在v6版本中,component和render被element属性给替代了,在element属性中,可以写JSX代码,children属性仍然保留了。

获取Route标签中的参数

  1. 仍然可以使用钩子函数useParams来获取参数
  2. 可以使用钩子函数useLocation来获取当前的地址信息
  3. 在v5版本使用的是useRouteMatch,在v6版本中使用的是useMatch函数,作用是用来检查当前url是否匹配某个路由。

useNavigate方法

该方法用于代替v5版本中的useHistory方法。

嵌套路由和Outlet

不使用Outlet来展示嵌套路由

在v6中,Route标签默认是使用严格匹配,但是在路径后面加个*就可以变成不严格匹配。

在子路由中,可以省略父路由的前缀路径

使用Outlet来展示嵌套路由

这样子只是将路由挂载进去了,但是没有决定让匹配到的组件在哪里显示

使用outlet标签可以决定匹配到的路由组件在父组件中显示的位置。

Navigate组件

useNavigate组件是通过钩子的形式进行页面跳转,Navigate组件是通过组件的形式进行页面跳转。

这两个东西都是自动进行跳转的。

//Navigate默认使用push模式进行跳转,在按下浏览器的回退的时候,又会重新执行这个代码,导致跳转,
//所以push模式下没办法回退,要想回退就必须使用replace模式
<Navigate to='www.cctv.com' replace/>

NavLink组件

这个组件在v5里面也有。

这个组件在v5中的时候有个activestyle属性,可以设置样式,但是在v6版本,这个属性不支持了,换成了style属性。

style属性的属性值是一个回调函数,返回值要一个对象,这个回调函数会默认传入一个对象,用于表示当前组件是否被激活。

可以通过useLocation(),获取NavLink的参数,NavLink的参数是传给属性state的,属性值是一个对象

路由鉴权

在vue中,是通过pinia存储token信息,然后通过判断路由信息来进行路由鉴权。

是的,React的钩子函数(Hooks)是对类组件中某些功能的抽象。在React的早期版本中,许多功能都是通过类组件来实现的,例如状态管理、生命周期方法等。随着React的发展,为了简化开发过程和提高可维护性,React团队引入了钩子函数的概念。

钩子函数提供了一种更加简洁和灵活的方式来使用React的功能,而不需要像类组件那样遵循特定的生命周期方法。通过使用钩子函数,我们可以将相关的功能组合在一起,使代码更加清晰和易于理解。

React的钩子函数包括:

  1. useState:用于在函数组件中添加状态。
  2. useEffect:用于在函数组件中执行副作用操作,如数据获取、订阅、手动更改DOM等。
  3. useContext:用于在函数组件中获取Context的值。
  4. useReducer:用于在函数组件中处理复杂的异步操作和状态逻辑。
  5. useCallback:用于在函数组件中返回记忆化的回调函数。
  6. useMemo:用于在函数组件中计算依赖项的最小值并返回结果。
  7. useRef:用于在函数组件中创建一个可变的ref对象。

通过使用钩子函数,我们可以更加灵活地构建React应用程序,并且可以避免一些类组件中的限制和复杂性。

为什么要鉴权

为什么的原因大家都清楚。

鉴权的难点在于:

  1. 我们以前是通过判断数据是否存在来进行跳转,但是这个方法只有在不知道页面路径的时候才管用,如果一旦知道路径,直接输入路径就可以访问对应页面,这个判断就形同虚设。

鉴权

引入库的形式

在React中,你可以使用react-router-config这个库来进行路由鉴权。这个库可以帮助你配置静态路由,并基于类似vue的路由鉴权想法进行鉴权。

首先,你需要在router.js中设置一个路由数组,并在每个路由对象中添加一个requiresAuth属性。如果requiresAuth为true,那么只有经过鉴权的用户才能访问该路由。

然后,你可以使用react-router-config生成静态的路由。在app.js中,你可以使用React.createElement方法来创建路由,并传递一个authed属性来控制是否渲染该路由。如果authed为false,那么该路由将被隐藏。

另外,你还可以使用react-router-config提供的utils/renderRoutes.js来渲染路由。这个文件中的源码增加了一个authed和authPath属性,以及一个route.requiresAuth属性。如果route.requiresAuth为false或者authed为true或者route.path === authPath(参数默认值'/login'),那么就渲染页面,否则就渲染authPath页面,并记录从哪个页面跳转。

最后,你还需要设计全局组件来管理是否登录。你可以在主路由模块index.js中引入这个组件,并通过监听路由变化来实现鉴权。例如,getUserConfirmation钩子就是做这件事情的。

以上就是在React中进行路由鉴权的基本步骤,你可以根据具体的需求进行修改和调整。

原生的形式

当别人通过路径来进行访问的时候,先判断有没有登录然后进行跳转。

使用本地存储

解决页面刷新之后重新登录的问题。

在React中实现数据持久化的一种常见方式是使用localStorage。localStorage 是一种 Web 存储 API,可以用来存储键值对,其中的值可以是任何类型(字符串、数字、对象、数组等)。

下面是一个使用 localStorage 实现数据持久化的简单例子:

  1. 存储数据:
localStorage.setItem('key', 'value');
  1. 获取数据:
const data = localStorage.getItem('key');
  1. 删除数据:
localStorage.removeItem('key');

注意,由于 localStorage 只能存储字符串,所以在存储和获取复杂数据类型(如对象或数组)时,需要使用 JSON.stringify() 和 JSON.parse() 方法进行序列化和反序列化。

例如,如果你有一个对象 user:

const user = { name: 'John', age: 30 };  
localStorage.setItem('user', JSON.stringify(user));

然后你可以这样获取它:

const userData = localStorage.getItem('user');  
const user = JSON.parse(userData);

但是,这种方式虽然简单,却存在一些问题。例如,如果你试图存储一个包含循环引用的对象,JSON.stringify() 会抛出错误。此外,localStorage 的大小限制(通常是5MB)可能会成为问题,尤其是当你需要存储大量数据时。因此,对于更复杂的需求,你可能需要考虑使用一个专门的库或服务来帮助你实现数据持久化。

可以传入一个回调函数。

用户的超时登出

当用户的登录时长到了的时候就自动登出。

要是用户自主登出,就应该清掉定时器。

黑马Router6

安装

npm i react-router-dom

快速开始

import * as React from "react";
import * as ReactDOM from "react-dom/client";
import { createBrowserRouter,RouterProvider} from "react-router-dom";
import "./index.css";
//1.创建管理路由的路由实例,传入一个数组
const router = createBrowserRouter([
  {
    path: "/",
    element: <div>Hello world!</div>,
  },
  {
    path: "/login",
    element: <div>登录页!</div>,
  }
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
  //2.注入路由实例
    <RouterProvider router={router} />//这里会显示路由表里的第一个路由
  </React.StrictMode>
);

在vue中,是用use方法注入这些插件。

在react中,是用各个库的provider标签注入各自的插件。

在vue和react中,都使用了路由方法创建对应的路由实例,以此来管理路由。

在vue中,component表示组件。

在react中,element表示组件。

在react-router中,是用RouterProvider标签注入路由的。

在实际开发中,无论是在vue和react中,我们都应该把路由实例封装到一个文件中然后暴露出来,然后注入进框架中。

路由导航

因为各个路由之间是相互独立的,为了使它们之间产生关联,就必须有路由导航。

如HTML中的a标签就起到了路由导航的作用。

声明式导航(Link组件)

在UI代码中写Link组件。

就是通过Link组件进行路由跳转。

因为Link组件会被渲染为a标签,所以我们直接修改a标签的样式即可。

使用Link组件,只能跳转到路由实例里面指定的路由。

编程式导航(useNavigate钩子)

在JS代码中写useNavigate钩子函数。

路由参数的传递和获取

参数的传递

就是拼接字符串:

查询参数

写法:直接在Link组件和useNavigate方法的路径上写即可

?代表的是查询参数,&可以连接多个查询参数。

查询参数:查询参数值为这个的数据。

查询参数使用?代替/

路径参数

写法:必须在路由实例里面对应的路由写上占位符,写好占位符之后,就直接在对应的路径上写参数值。

路径参数:冒号:是占位符,:id表示跳转到id值为多少的路由。

路径参数才要使用/

参数的获取

查询参数的获取(useSearchParams钩子)
const [params] = useSearchParams();
let id = params.get('id')//获取参数名为id的参数。
路径参数的获取(useParams钩子)
const params = useParams();//不需要中括号了
let id = params.id//不需要get了,直接写占位符的参数名

嵌套路由

介绍和使用

实现步骤:

  1. 使用children属性配置路由嵌套关系
  2. 使用组件配置二级路由渲染位置

在vue中,是使用RouterView标签指定路由渲染位置,包括父级路由和子孙路由。

默认二级路由配置

即不需要访问二级路由地址,也可以让该二级路由正常显示出来。

用法:只需要去掉对应二级路由的path属性,然后给其设置一个index属性,且值为true。

在vue中如果要设置默认二级路由,只需要将path属性设置为空即可。

404路由(不在路由实例里的路由)

使用场景:当用户输入的url路径在整个实例路由配置中都找不到对应的path的时候,为了用户体验,我们就应该使用一个专门的报错组件来提醒用户,而这个就是404组件。

实现步骤:

    1. 自己写一个404组件
    2. 在路由表数组的末尾,以*号作为路由path配置路由,组件就用404组件

两种路由模式

介绍

各个主流框架的路由,常用的路由模式都有两种,history模式和hash模式。

React-Router:

history模式:createBrowerRouter函数创建

hash模式:createHashRouter函数创建

路由实例

在vue中是有路由实例的,通过获取路由实例来进行编程式导航和添加路径参数和查询参数。

但是在react-router中是没有路由实例的,但是可以通过useSearchParams和useParams获取路由参数和useNavigate进行路由导航来实现路由实例的功能。

通过这种方法来保证每次路由跳转都能保留路由参数。

获取路由路径

使用useLocation方法。

const a = useLocation();
console.log(a)

官网Route6

选择对应类型的路由器

我们建议所有的web项目都使用createBrowserRouter。

它使用完整的URL,而不是历史上web应用中常见的哈希URL (#this/stuff)。标准化了pushState。完整的url对SEO更好,对服务器渲染更好,并且与web平台的其他部分更兼容。

如果你的应用托管在一个静态文件服务器上,你需要将它配置为将所有请求发送到index.html,以避免收到404请求。

如果由于某种原因你不能使用完整的URL, createHashRouter是下一个最好的选择。

createBrowserRouter

这是所有React router web项目的推荐路由器。它使用DOM History API来更新URL和管理历史堆栈。它还支持v6.4数据api,如加载器、操作、获取器等。

createBrowserRouter 是 react-router-dom 中的一个函数,用于创建一个浏览器路由器组件。它有几个参数,以下是其主要的参数:

  1. history: 这是一个历史对象,用于管理 URL 的变化和导航。你可以使用 createBrowserHistory 或 createHashHistory 来创建一个历史对象。
  2. routes: 这是你要渲染的路由配置。它是一个 JSX 元素,可以包含嵌套的 和 组件。
  3. basename: (可选) 这是 URL 的基础路径。例如,如果你想从 example.com/redux-store 而不是 example.com 开始路由,你可以传递一个 basename="/redux-store"。
  4. staticContext: (可选) 如果你的应用需要静态上下文,你可以传递一个静态上下文对象。

这些是主要的参数,但可能还有其他可选参数或属性。为了获得最准确和最新的信息,建议查看 react-router-dom 的官方文档或源代码。

{
  path,//路由路径
  element,//该路径下要显示的组件
  errorElement,//用于给错误页面配置组件
  action,//用于get以外的操作
  loader,//用于get操作
  children,//子路由
  index,//用于不写path的时候,直接显示该路由
}

//全部属性以下面这个为准
interface RouteObject {
  path?: string;
  index?: boolean;
  children?: React.ReactNode;
  caseSensitive?: boolean;
  id?: string;
  loader?: LoaderFunction;
  action?: ActionFunction;
  element?: React.ReactNode | null;
  hydrateFallbackElement?: React.ReactNode | null;
  errorElement?: React.ReactNode | null;
  Component?: React.ComponentType | null;
  HydrateFallback?: React.ComponentType | null;
  ErrorBoundary?: React.ComponentType | null;
  handle?: RouteObject["handle"];
  shouldRevalidate?: ShouldRevalidateFunction;
  lazy?: LazyRouteFunction<RouteObject>;
}
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} />
  );
function createBrowserRouter(
  routes: RouteObject[],
  opts?: {
    basename?: string;
    future?: FutureConfig;
    hydrationData?: HydrationState;
    window?: Window;//这里还有个window属性
  }
): RemixRouter;
createBrowserRouter([
  {
    path: "/",
    element: <Root />,
      loader: rootLoader,
      //在children属性上嵌套路由的Route对象数组。
      children: [
        {
          path: "events/:id",
          element: <Event />,
          loader: eventLoader,
        },
      ],
      },
]);

应用程序的basename,用于不能部署到域的根目录,而是一个子目录的情况:

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

当链接到根目录时,尾斜杠将被拼接上去。

React Router中的basename属性主要用于为所有路由添加一个基准URL。具体来说,当使用basename属性时,路由的路径将从该属性值开始,而不是从根路径开始。例如,如果设置了basename="/demo",那么链接将会渲染成

请注意,为了使basename属性生效,需要将其放在Router组件的标签内。

//路由到达前
createBrowserRouter(routes, {
  basename: "/app",
});
<Link to="/" />; // results in <a href="/app" />

//路由到达后
createBrowserRouter(routes, {
  basename: "/app/",
});
<Link to="/" />; // results in <a href="/app/" />

一组可选的未来标志来启用这个路由器。我们建议尽早选择新发布的未来标志,以便最终迁移到v7:

const router = createBrowserRouter(routes, {
  future: {
    // Normalize `useNavigation()`/`useFetcher()` `formMethod` to uppercase
    v7_normalizeFormMethod: true,
  },
});

以下是当前可用的未来标志:

FlagDescription
v7_fetcherPersist延迟活动获取器清理,直到它们返回到空闲状态
v7_normalizeFormMethod正常化useNavigation().formMethod必须是一个大写的HTTP方法
v7_partialHydration支持部分水合为服务器渲染的应用程序
v7_prependBasename在路由器名称前加上导航/获取路径
v7_relativeSplatPath修复splat路由中的相对路径解析错误

当服务器渲染和选择退出自动水合作用时,hydrationData选项允许您从服务器渲染传入水合作用数据。这几乎总是你从handler.query返回的StaticHandlerContext值的数据子集:

const router = createBrowserRouter(routes, {
  hydrationData: {
    loaderData: {
      // [routeId]: serverLoaderData
    },
    // may also include `errors` and/or `actionData`
  },
});

你几乎总是会包含一套完整的loaderData来为服务器渲染的应用程序提供支持。但在高级用例中(比如Remix的clientLoader),你可能只想为服务器上渲染的一些路由包含loaderData。如果你想启用部分loaderData和选择进入颗粒路由。使用hydratfallback时,需要将来启用。v7_partialHydration国旗。在此标志之前,任何提供的loaderData都被认为是完整的,不会导致在初始化时执行路由加载器。

当指定此标志时,加载器将在两种情况下运行初始水合:

没有提供水合作用数据

在这些情况下,HydrateFallback组件将在初始水化时渲染

加载程序。水合物属性设置为true

这允许您运行加载程序,即使您没有在初始化时呈现回退(即,初始化数据缓存)。

const router = createBrowserRouter(
  [
    {
      id: "root",
      loader: rootLoader,
      Component: Root,
      children: [
        {
          id: "index",
          loader: indexLoader,
          HydrateFallback: IndexSkeleton,
          Component: Index,
        },
      ],
    },
  ],
  {
    future: {
      v7_partialHydration: true,
    },
    hydrationData: {
      loaderData: {
        root: "ROOT DATA",
        // No index data provided
      },
    },
  }
);

对于浏览器开发工具插件等环境或测试使用与全局窗口不同的窗口非常有用。

createHashRouter

如果你不能配置你的web服务器来引导所有的流量到你的React router应用程序,这个路由器是有用的。它将使用URL的哈希(#)部分来管理“应用程序URL”,而不是使用正常的URL。不建议使用散列url。

除此之外,它在功能上与createBrowserRouter相同。

import * as React from "react";
import * as ReactDOM from "react-dom";
import {
  createHashRouter,
  RouterProvider,
} from "react-router-dom";

import Root, { rootLoader } from "./routes/root";
import Team, { teamLoader } from "./routes/team";

const router = createHashRouter([
  {
    path: "/",
    element: <Root />,
    loader: rootLoader,
    children: [
      {
        path: "team",
        element: <Team />,
        loader: teamLoader,
      },
    ],
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <RouterProvider router={router} />
);

createMemoryRouter

内存路由器不使用浏览器的历史记录,而是在内存中管理自己的历史记录堆栈。它主要用于测试和组件开发工具,如Storybook,但也可用于在任何非浏览器环境中运行React Router。

createStaticRouter

当你想利用数据路由器在服务器(即Node或其他Javascript运行时)上进行渲染时,使用createStaticRouter。有关更完整的概述,请参阅服务器端呈现指南。

createStaticHandler

在服务器端通过呈现应用程序之前,createStaticHandler用于在服务器(即Node或其他Javascript运行时)上执行数据获取和提交。有关更完整的概述,请参阅服务器端呈现指南。

RouterProvider

declare function RouterProvider(
  props: RouterProviderProps
): React.ReactElement;
//该标签只有三个属性:router、fallbackElement、future
interface RouterProviderProps {
  fallbackElement?: React.ReactNode;
  router: Router;
  future?: Partial<FutureConfig>;
}

StaticRouterProvider

一个从createStaticRouter()中接受一个路由器,从createStaticHandler()中接受一个上下文,并在服务器(即Node或其他Javascript运行时)上呈现你的应用程序。有关更完整的概述,请参阅服务器端呈现指南。

import {
  createStaticHandler,
  createStaticRouter,
  StaticRouterProvider,
} from "react-router-dom/server";
import Root, {
  loader as rootLoader,
  ErrorBoundary as RootBoundary,
} from "./root";

const routes = [
  {
    path: "/",
    loader: rootLoader,
    Component: Root,
    ErrorBoundary: RootBoundary,
  },
];

export async function renderHtml(req) {
  let { query, dataRoutes } = createStaticHandler(routes);
  let fetchRequest = createFetchRequest(req);
  let context = await query(fetchRequest);

  // If we got a redirect response, short circuit and let our Express server
  // handle that directly
  if (context instanceof Response) {
    throw context;
  }

  let router = createStaticRouter(dataRoutes, context);
  return ReactDOMServer.renderToString(
    <React.StrictMode>
    <StaticRouterProvider
  router={router}
  context={context}
    />
    </React.StrictMode>
  );
}

路由组件

其实就是上面各种路由器的组件版本。

路由属性

Route路由中大多属性讲解

路由可能是React Router应用中最重要的部分。它们将URL段与组件、数据加载和数据突变耦合在一起。通过路由嵌套,复杂的应用程序布局和数据依赖关系变得简单明了。

路由是传递给路由器创建函数的对象:

const router = createBrowserRouter([
  {
    // it renders this element
    element: <Team />,

    // when the URL matches this segment
    path: "teams/:teamId",

  // with this data loaded before rendering
  loader: async ({ request, params }) => {
  return fetch(
    `/fake/api/teams/${params.teamId}.json`,
    { signal: request.signal }
  );
},

  // performing this mutation when data is submitted to it
  action: async ({ request }) => {
  return updateFakeTeam(await request.formData());
    },

    // and renders this element in case something went wrong
    errorElement: <ErrorBoundary />,
  },
]);

你也可以用JSX和createRoutesFromElements来声明你的路由,元素的props和路由对象的属性是一样的:

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route
  element={<Team />}
  path="teams/:teamId"
  loader={async ({ params }) => {
  return fetch(
    `/fake/api/teams/${params.teamId}.json`
  );
}}
action={async ({ request }) => {
  return updateFakeTeam(await request.formData());
}}
errorElement={<ErrorBoundary />}
  />
  )
);

这两种风格都是不鼓励的,行为是相同的。在本文档的大部分内容中,我们将使用JSX风格,因为这是大多数人在React Router环境中习惯使用的风格。

注意:

当使用RouterProvider时,如果你不想指定一个React元素(即element={}),你可以指定一个Component(即Component={MyComponent}), React Router会在内部为你调用createElement。你应该只对RouterProvider应用这么做,因为在中使用Component会破坏React在渲染中重用已创建元素的能力。

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

如果一个路径段以:开头,那么它就变成了一个“路径参数”。当路由匹配URL时,路径参数将从URL中解析出来,并作为参数提供给其他路由器api。

<Route
	path="/teams/:teamId"
	loader={({ params }) => {
  	console.log(params.teamId); 
	}}
	action={({ params }) => {}}
	element={<Team />}
/>;

  //获取路径参数
  function Team() {
    let params = useParams();
  	console.log(params.teamId);
	}

可选参数:

<Route
//表示该路径参数是可选的,不是必填的
path="/:lang?/categories"
loader={({ params }) => {
console.log(params["lang"]); 
  }}
  action={({ params }) => {}}
  element={<Categories />}
/>;

// 
function Categories() {
  let params = useParams();
  console.log(params.lang);
}
<Route path="/project/task?/:taskId" />

*号:

<Route
	path="/files/*" //路径里面加个*,表示匹配该路径后面所有的路由
	loader={({ params }) => {
  	console.log(params["*"]); 
	}}
	action={({ params }) => {}}
	element={<Team />}
/>;
 
  function Team() {
    let params = useParams();
    console.log(params["*"]);
  }

你可以解构*,你只需要给它赋一个新名字。一个常见的名字是splat:

let { org, "*": splat } = params;
布局路由
//省略path参数的路由作为布局路由,它参与UI嵌套,但不向URL添加任何路径。
<Route
	element={
  	<div>
  		<h1>Layout</h1>
  		<Outlet />
  	</div>
	}
>
  <Route path="/" element={<h2>Home</h2>} />
  <Route path="/about" element={<h2>About</h2>} />
</Route>
index属性

确定路由是否为索引路由。索引路由在父路由的URL上呈现到父路由的Outlet中(就像默认的子路由一样)。

<Route path="/teams" element={<Teams />}>
  <Route index element={<TeamsIndex />} />
  <Route path=":teamId" element={<Team />} />
  </Route>
caseSensitive(大小写)

指示路由是否匹配case:

<Route caseSensitive path="/wEll-aCtuA11y" />

在React Router中,caseSensitive属性用于指定匹配路由时是否区分大小写。默认情况下,caseSensitive属性的值为false,表示不区分大小写。

当caseSensitive属性的值为true时,路由匹配将区分大小写。这意味着在URL中,路径的每个字母都将被视为区分大小写,只有完全匹配的路径才会被视为有效路由。

loader

路由加载器在路由呈现之前被调用,并通过useLoaderData为元素提供数据。

<Route
path="/teams/:teamId"
loader={({ params }) => {
  return fetchTeam(params.teamId);
}}
/>;

function Team() {
  let team = useLoaderData();
  // ...
}

如果您没有使用像createBrowserRouter这样的数据路由器,那么这将不起任何作用。

action

当表单、获取器或提交向路由发送提交时,调用路由的action。

<Route
path="/teams/:teamId"
action={({ request }) => {
  const formData = await request.formData();
  return updateTeam(formData);
}}
/>

如果您没有使用像createBrowserRouter这样的数据路由器,那么这将不起任何作用。

element和Component

这两个都可以生成组件,但是推荐用element。因为component会破坏React跨渲染重用已创建元素的能力。

errorElement / ErrorBoundary

当路由在渲染时抛出异常时,无论是在加载器中还是在动作中,这个React元素/组件都会渲染,而不是正常的元素/组件。

如果你想自己创建React元素,使用errorElement:

<Route
	path="/for-sale"
	// if this throws an error while rendering
	element={<Properties />}
  // or this while loading properties
  loader={() => loadProperties()}
  // or this while creating a property
  action={async ({ request }) =>
  	createProperty(await request.formData())
  }
  // then this element will render
  errorElement={<ErrorBoundary />}
/>

否则使用ErrorBoundary(reactRouter帮我们创建错误页面), React Router会为你创建React元素:

<Route
	path="/for-sale"
	Component={Properties}
	loader={() => loadProperties()}
  action={async ({ request }) =>
    createProperty(await request.formData())
  }
  ErrorBoundary={ErrorBoundary}
/>

如果您没有使用像createBrowserRouter这样的数据路由器,那么这将不起任何作用

hydrateFallbackElement / HydrateFallback

如果你正在使用服务器端渲染,并且你正在利用部分水化,那么你可以指定一个元素/组件在应用程序的初始水化期间为非水化路由渲染。

如果您没有使用像createBrowserRouter这样的数据路由器,那么这将不起任何作用

这只适用于更高级的用例,如Remix的clientLoader功能。大多数SSR应用不需要利用这些路由属性。

请参阅hydrateFallbackElement文档了解更多细节。

lazy

为了让你的应用包更小,并支持对路由进行代码拆分,每个路由都可以提供一个异步函数来解析路由定义中不匹配路由的部分(loader、action、Component/element、ErrorBoundary/errorElement等)。

每个lazy函数通常都会返回动态导入的结果。

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

然后在你的lazy路由模块中,导出你想要为路由定义的属性:

export async function loader({ request }) {
  let data = await fetchData(request);
  return json(data);
}

export function Component() {
  let data = useLoaderData();

  return (
    <>
    <h1>You made it!</h1>
    <p>{data}</p>
    </>
  );
}

如果您没有使用像createBrowserRouter这样的数据路由器,那么这将不起任何作用

action

路由action是“写”到路由loader“读”。它们为应用程序提供了一种使用简单的HTML和HTTP语义执行数据突变的方法,而React Router抽象了异步UI和重新验证的复杂性。这为您提供了HTML + HTTP(其中浏览器处理异步和重新验证)与现代spa的行为和用户体验功能的简单心智模型。

此功能仅在使用createBrowserRouter时有效。

<Route
	path="/song/:songId/edit"//这里有动态数据段songId
	element={<EditSong />}
  action={async ({ params, request }) => {
    let formData = await request.formData();
  	return fakeUpdateSong(params.songId, formData);
  }}
	loader={({ params }) => {
  	return fakeGetSong(params.songId);
	}}
/>

当应用向你的路由发送一个非get提交(“post”、“put”、“patch”、“delete”)时,action就会被调用。这可以通过几种方式发生:

// 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",
});

参数:

路由参数是从动态segments中解析出来的,然后传递给你的动作。这对于确定要改变的资源非常有用:

<Route
	path="/projects/:projectId/delete"
	action={({ params }) => {
  	return fakeDeleteProject(params.projectId);
	}}
/>

请求:

这是一个发送到路由的Fetch Request实例。最常见的用例是解析来自请求的FormData

<Route
	action={async ({ request }) => {
  	let formData = await request.formData();
 	 // ...
	}}
/>

起初,action接收“请求”可能看起来很奇怪。你写过这行代码吗?

<form
	onSubmit={(event) => {
  	event.preventDefault();
 	 // ...
	}}
/>

你到底在阻止什么?

没有JavaScript,只有普通的HTML和HTTP web服务器,这个被阻止的默认事件实际上是非常棒的。浏览器会将表单中的所有数据序列化为FormData,并将其作为新请求的主体发送给服务器。就像上面的代码一样,React Router

会阻止浏览器发送该请求,而是将请求发送给你的路由action!这使得高度动态的web应用程序具有简单的HTML和HTTP模型。

请记住,formData中的值是在表单提交时自动序列化的,因此输入需要一个名称。

<Form method="post">
  <input name="songTitle" />
  <textarea name="lyrics" />
  <button type="submit">Save</button>
</Form>;

// accessed by the same names
formData.get("songTitle");
formData.get("lyrics");

可选序列化类型:

请注意,当使用useSubmit时,您也可以传递encType: "application/json"或encType: "text/plain"来将您的payload序列化为request.json()或request.text()。

返回响应:

虽然你可以从一个动作中返回任何你想要的东西,并从useActionData中访问它,你也可以返回一个web Response。

加入actions:

你可以抛出你的action来打破当前调用栈(停止运行当前代码),React Router就会沿着“错误路径”重新开始。

<Route
	action={async ({ params, request }) => {
  	const res = await fetch(
    	`/api/properties/${params.id}`,
    	{
      	method: "put",
      	body: await request.formData(),
    	}
  	);
  	if (!res.ok) throw res;
  	return { ok: true };
  }}
/>

每条路由处理多个action:

一个相当常见的问题是“如果我需要在我的action中处理多个不同的action该怎么办?”有几种方法可以做到这一点,但通常最简单的是在上放置一个名称/值,并在操作中使用它来决定执行哪个代码(这是正确的-提交按钮可以有名称/值属性!):

async function action({ request }) {
  let formData = await request.formData();
  let intent = formData.get("intent");

  if (intent === "edit") {
    await editSong(formData);
    return { ok: true };
  }

  if (intent === "add") {
    await addSong(formData);
    return { ok: true };
  }

  throw json(
    { message: "Invalid intent" },
    { status: 400 }
  );
}

function Component() {
  let song = useLoaderData();

  // When the song exists, show an edit form
  if (song) {
    return (
      <Form method="post">
      <p>Edit song lyrics:</p>
    {/* Edit song inputs */}
    <button type="submit" name="intent" value="edit">
      Edit
      </button>
      </Form>
    );
  }

  // Otherwise show a form to add a new song
  return (
    <Form method="post">
    <p>Add new lyrics:</p>
  {/* Add song inputs */}
  <button type="submit" name="intent" value="add">
    Add
    </button>
    </Form>
  );
}

如果按钮名称/值不适合您的用例,您还可以使用隐藏输入来发送和意图,或者您可以通过 prop提交不同的HTTP方法(POST用于添加,PUT/PATCH用于编辑,DELETE用于删除)。

errorElement

hydrateFallbackElement

lazy(路由懒加载)

只有这种写法才能通过ts检查。

而且下面这种写法无法加载出组件,所以我们用上面这种写法来进行懒加载。

loader

数据的接收需要通过useLoaderData, 使用很简单直接导入调用就行。

const data: any = useLoaderData();

shouldRevalidate

组件

常用钩子

useRoutes()配置路由表

根据路由表,动态创建 和

import { useRoutes } from 'react-router-dom'

// 定义路由表
const elements = useRoutes([{
    path: '/about',
    element: <About />
}, {
    path: '/home',
    element: <Home />
}, {
    path: '/',
    element: <Navigate to='/about' />
}])

// 在配置路由管理的地方直接插入即可
{elements}

// 子路由直接使用<Outlet/> 标签占位即可
<Outlet/>

useNavigate()编程式导航

返回一个函数用来实现编程式路由导航

useHistory()钩子在v6版本废弃了。用useNavigate()钩子代替。

import { useNavigate } from 'react-router-dom'

navigat('detail', {
    replace: false,
    state: message
})

useParams()获取路径参数

接收当前路由的 params 参数,对标 5 路由组件的 match.params

import { useParams } from 'react-router-dom'

const { x, xx, xxx } = useParams()

// 也可以用 useMatch 但是正常人不会用的,因为它需要传入全路径:
// useMatch('/home/message/detail/:id/:title/:info')

useSearchParams()获取查询参数

用于读取和修改当前路由 URL 中的查询字符串(就是search参数)

返回一个包含两个值的数组:当前search集合,更新search集合的函数

import { useSearchParams } from 'react-router-dom'

// 获取search参数
const [search, setSearch] = useSearchParams()
const x = search.get('x')
const xx = search.get('xx')
const xxx = search.get('xxx')

// 修改search参数
setSearch('x=5000&xx=新标题&xxx=小猪佩奇')

useLocation()获取路由路径

获取当前路由 loacation 值,对标 5 路由组件的 location 属性

import { useLocation } from 'react-router-dom'

// 直接连续结构获取 location 中的 state 的属性
const { state: { id, title, info } } = useLocation()

在React Router库中,useLocation是一个重要的钩子函数,用于在函数式组件中获取当前页面的URL地址信息。它返回一个包含当前路径、搜索参数和哈希值等信息的location对象。

useLocation的作用是帮助开发者获取当前页面的URL位置区域信息,包括pathname、search和hash等部分。通过useLocation,开发者可以在功能组件中轻松地获取和响应当前URL位置区域的变化。

useLocation的基本用法是在功能组件中引入useLocation钩子函数,它将返回一个location对象,可以通过该对象访问当前页面的URL信息。例如,可以使用location.pathname获取当前页面的路径,使用location.search获取查询参数等。

此外,在React Router中,还有一个重要的钩子函数是useHistory,它返回一个包含历史记录信息的history对象。通过这个对象,开发者可以执行路由跳转操作,例如使用history.push方法来跳转到新的页面。

总之,useLocation和useHistory是React Router库中非常重要的钩子函数,它们可以帮助开发者在React应用程序中轻松地处理路由和导航。

useMatch()路径严格匹配

返回当前匹配信息,对标 5 路由组件的 match 属性

非特殊情况正常人不会用的,因为它需要传入全路径:

// 路由配置
<Route path='/home/message/detail/:id/:title/:info' element={<Message/>}/>

// Message组件引入 useParams
import { useParams } from 'react-router-dom'
// Message组件获取匹配信息
const match = useMatch('/home/message/detail/:id/:title/:info')

// match 对象输出如下(其他方式传参pathxxx不会有后缀)
{
    params:  {},
	pathname: "/home/message/detail/x/xx/xxx",
	pathnameBase: "/home/message/detail/x/xx/xxx",
	pattern: {
        path: "/home/message/detail/:id/:title/:info"
        caseSensitive: false,
        end: true,
    }
}

useMatch 是 React Router 库中的一个钩子(hook),用于返回当前路径是否与给定的模式匹配。这个钩子函数接受一个模式作为参数,并返回一个布尔值,表示当前路径是否与该模式匹配。

使用 useMatch 可以方便地判断当前路径是否符合特定的条件,从而执行相应的逻辑。例如,你可以使用 useMatch 来判断用户是否在登录状态下,或者判断用户是否在访问特定的页面。

下面是一个简单的示例,演示了如何使用 useMatch 来判断当前路径是否匹配指定的模式:

import { useMatch } from 'react-router-dom';  
  
function ExampleComponent() {  
  const isPathMatched = useMatch('/example'); // 判断当前路径是否匹配 "/example"  
  
  if (isPathMatched) {  
    // 当前路径匹配 "/example",执行相应的逻辑  
    return <h1>当前路径匹配 "/example"</h1>;  
  } else {  
    // 当前路径不匹配 "/example",执行其他逻辑  
    return <h1>当前路径不匹配 "/example"</h1>;  
  }  
}

在上面的示例中,useMatch('/example') 将返回一个布尔值,表示当前路径是否匹配 "/example"。根据返回值,我们可以执行相应的逻辑。

请注意,useMatch 是基于正则表达式进行匹配的,因此可以使用正则表达式的元字符来定义匹配模式。例如,useMatch('/users/:id') 将匹配以 "/users/" 开头,后面跟着一个参数的路径。

useInRouterContext()

如果组件在 Router 的上下文中呈现(处在路由组件内),则 useInRouterContext() 钩子返回 true,否则返回 false

useNavigationType()导航类型

返回当前的导航类型(用户是如何来到当前页面的)

返回值:POP、PUSH、REPLACE

备注:POP是指在浏览器中直接打开了这个路由组件(刷新页面或者路由首页)

useOutlet()嵌套路由

用来呈现当前组件中要渲染的嵌套路由

const result = useOutlet()
// 如果嵌套路由没挂载:null
// 如果嵌套路由已挂载:嵌套路由对象

useResolvedPath()

给定一个URL值,解析其中的 path、search、hash 值

获取请求

全局属性

action和loader的执行时机

react-router-dom 是一个用于 React 的路由库,提供了基于浏览器的路由功能。在 react-router-dom 的 useRoutes 钩子中,你可以使用 data 属性来定义路由。

在 data 属性中,你可以定义两个属性:action 和 loader。

  1. action
    • 执行时机:当路由匹配时,会立即执行这个 action。
    • 用途:通常用于异步操作,如 API 请求。并没有说什么时候会执行完成。
    • 返回值:返回值将作为组件的 props 传递给匹配的组件。
  1. loader
    • 执行时机:当路由匹配时,loader 会被调用,但它的结果会在实际渲染组件时被使用。也就是说,loader 的执行会在路由匹配之后,但在实际渲染组件之前。
    • 用途:通常用于异步加载数据,这些数据将作为组件的 props 传递给匹配的组件。
    • 返回值:返回值将作为组件的 props 传递给匹配的组件。

简而言之,action 和 loader 都可以用于执行异步操作,但它们的执行时机和用途略有不同。action 用于执行操作并立即返回结果,而 loader 用于加载数据并在渲染时使用这些数据。

既然返回值是传入props的,那么说明执行的异步函数,作用必须是获取一次性的数据,即不能根据条件改变,所以action和loader这些通常用于获取组件渲染的数据,而不用于获取交互的数据。