Skip to content

❤React-ReactRouter路由的使用

React Router 在 2021 年 11 月份的时候更新 v6 的版本,本次主要学习的也是v6,里面更改了很多新写法特性!

1、路由的认识

官网给他定义是一个库,不是一个框架。

React官方并没有提供路由库,路由插件,而是推荐我们使用React结合ReactRouter来进行路由的映射。

正常的路由开发模式分为以下三种:

  • 编程式路由:自己在页面中写代码进行路由编程,包括映射、路由引入。
  • 配置式路由:将路由映射写到配置文件中,剩下的就是自动渲染。
  • 约定式路由:无需配置路由,你的项目文件系统就是路由。(Next就是这种方式)

先来看看Vuejs配置式路由:

js
src/router/index.js

import VueRouter from "vue-router"
import Login from "./Login.vue"

const routes = [
  {
       path:"/login",
       name:"Login"
       component:Login
  }
]
const router = new VueRouter({
   routes,
   mode:"hash"
})

export default router

2、路由安装下载

下载React路由

js
yarn add react-router-dom

3、路由的使用

我们先在App.jsx 组件搭建路由(四个页面主要是后台首页、登陆页面、后台文章、后台用户)

App.jsx之中引入页面

js

import Home from '@/pages/Home';
import Login from '@/pages/Login';
import User from '@/pages/User';
import Article from '@/pages/Article';

App.jsx之中路由的引入和使用

js
import { BrowserRouter, Routes, Route } from "react-router-dom"

 <BrowserRouter>
      {/* 路由映射列表 */}
       <Routes>
        {/* 路由具体路径匹配 */}
         <Route path="/" element={<Home></Home>}></Route>
         <Route path="/login" element={<Login></Login>}></Route>
         <Route path="/user" element={<User></User>}></Route>
         <Route path="/article" element={<Article></Article>}></Route>
       </Routes>
</BrowserRouter>

4、路由详细说明:

路由大致认识

路由器目前有两种(:BrowserRouter、HashRouter),决定了当前路由的模式。

BrowserRouter:默认采用history模式

HashRouter:采用hash模式。路径访问的时候需要/#/

路由映射:Routes、Route主要负责进行路由路径匹配,提供渲染的组件

Routes:表示可以包含多个映射规则。从上到小的进行匹配。当匹配成功结束匹配

Route:进行路由映射,path路由路径,element提供映射组件。指定的这个地方渲染组件

路由导航:Link、NavLink

通过Link和NavLink组件可以实现路由的切换,类似于Vue之中的router-link进行对号入座!

路由映射规则

默认索引和重定向 需求:当我们点击进来以后首先进入的是我们的home主页面:index 的作用

默认进来匹配的组件就是Home组件。默认索引。index只能用一次

plain
xml

 代码解读
复制代码<Routes>
<Route path="/" index element={<Home></Home>}></Route>
</Routes>

重定向规则

js
javascript
复制代码
import {Navigate} from "react-router-dom"

<Routes>
<Route path="/" element={<Navigate to="/login"></Navigate>}></Route>
</Routes>

我们还可以用重定向解决404的问题

完整页面大致如下:

js
import AntdComp from "./components/AntdComp";
import Header from "./components/Header";
import Login from "./views/Login";
import Register from "./views/Register";
import ForgetPassword from "./views/ForgetPassword";
import { Button, ConfigProvider, Space } from 'antd';
import NotFind from "./views/NotFind";
import { BrowserRouter,HashRouter, Routes, Route,Link,NavLink,Navigate } from "react-router-dom"
function App() {
 return (
   <ConfigProvider
     theme={{
       token: {
         // Seed Token,影响范围大
         colorPrimary: '#7cb305'
      },
    }}
   >
    {/* 路由器 */}
     <BrowserRouter>
      {/* 路由映射列表 */}
       <ul>
         <li>
           <Link to="/register">注册</Link>
         </li>
         <li>
           <NavLink to="/forget">忘记密码</NavLink>
         </li>
       </ul>
       <Routes>
        {/* 路由具体路径匹配 */}
         <Route path="/" element={<Navigate to="/login"></Navigate>}></Route>
         <Route path="/login" element={<Login></Login>}></Route>
         <Route path="/register" element={<Register></Register>}></Route>
         <Route path="/forget" element={<ForgetPassword></ForgetPassword>}></Route>
         <Route path="/404" element={<NotFind></NotFind>}></Route>
         <Route path="*" element={<Navigate to="/404"></Navigate>}></Route>
       </Routes>
     </BrowserRouter>
   </ConfigProvider>
);
}

export default App;

5、路由组件的封装

根组件下面新建文件夹router=>index.tsx ,这个文件夹下面就专门负责我们的路由

接下来我们把路由给拿出来单独放到一文件夹里面

js
import { lazy } from 'react'; //lazy懒加载
import { BrowserRouter, Routes, Route } from 'react-router-dom';


import Home from '@/pages/Home';
import Login from '@/pages/Login';
import User from '@/pages/User';
import Article from '@/pages/Article';

function getRouter() {
  return <>
    <BrowserRouter>
      {/* 路由映射列表 */}
      <Routes>
        {/* 路由具体路径匹配 */}
        <Route path="/" index element={<Home></Home>}></Route>
        <Route path="/login" element={<Login></Login>}></Route>
        <Route path="/user" element={<User></User>}></Route>
        <Route path="/article" element={<Article></Article>}></Route>
      </Routes>
    </BrowserRouter></>
}
export default getRouter

6、重定向路由redirect(Navigate)

接下来我们输入http://localhost:3000/a 却发现一片空白,那么我们想要输入不匹配的直接跳转到我们的首页应该如何做呢

先看看之前v5版本的重定向如何做的

在我们访问'/' 的时候直接就重定向到了‘/filems’ 这个路由

在这里确实遇到了坑,就是写的完全一样,但是就是不生效,前端瞬息万变,强烈建议有些东西看看会了就行,记住了也没啥用,最重要的就是理解并且会查阅相关的文档,这里新版本的v6写法已经变成了下面这样子:(含义就是高改变了以后 v6 中的重定向更加简洁和直观)

主要是利用其中的Navigate 进行冲定向

js
import { BrowserRouter as Router, Routes, Route ,Navigate} from 'react-router-dom';


{/* 假设需要在某个条件下进行重定向 */}
<Route path="/article" element={<Navigate to="/new-url" />} />

{/* 或者根据条件返回一个 Navigate 组件 */}
<Route path="/another-old-url" element={<User></User>} />

{/* 其他路由 */}
<Route path="/new-url" element={<User></User>} />

所以当我们访问/article 会自动重新定向去 /new-url 地址,展示User组件

7、404 界面

当我们找不到未匹配的路径的时候,我们现在的页面一片空白,接下来我们想找不到页面的时候去我们的404界面,应该怎么做呢

新建一个NotFind.tsx 界面,这里也是巧妙的利用我们的Navigate的功能

js
<Route path="/404" element={<NotFind></NotFind>}></Route>
<Route path="*" element={<Navigate to="/404"></Navigate>}>

访问http://localhost:3000/8888地址,自动重定向到了我们的404界面

8、React.lazy 优化路由

认识

我们发现加了路由以后我们的加载缓慢了很多,React.lazy可以减少我们应用的初始加载时间,提升用户体验,对于大型单页应用(SPA)或需要优化加载时间的应用特别有用

React.lazy 是 React 提供的一个动态导入组件的方法,作用是需要时才加载组件,而不是在应用初始化时就加载所有组件,从而提高应用的性能和加载速度。

React.lazy 函数接受一个函数作为参数,动态导入组件。当组件需要被渲染时,React 将调用这个函数来加载组件。加载完成后,组件将被缓存,以便在将来的渲染中重用。

React.lazy 结合 Suspense 组件使用时,可以优雅地处理动态加载组件时的 loading 状态,使代码更加清晰和易于维护。

使用lazy,优化我们的router.tsx

js
const Home = lazy(() => import('@/pages/Home'));
const Login = lazy(() => import('@/pages/Login'));
const NotFind = lazy(() => import('@/pages/NotFind'));

9、使用Suspense 默认加载效果

v6之前的版本使用

js
// App.js
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

const Login = lazy(() => import('./Login'));
const Admin = lazy(() => import('./Admin'));

const App = () => {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Switch>
          <Route exact path="/" component={Login} />
          <Route path="/admin" component={Admin} />
        </Switch>
      </Suspense>
    </Router>
  );
};

export default App;

v6版本对此作了一些调整

js
// App.js
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Login = lazy(() => import('./Login'));
const Admin = lazy(() => import('./Admin'));

const App = () => {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/" element={<Login />} />
          <Route path="/admin" element={<Admin />} />
        </Routes>
      </Suspense>
    </Router>
  );
};
export default App;

刷新页面看看我们的加载效果

10、嵌套路由 Link和 Outlet的使用

接下来我们在文章之中添加两个种类的文章类型,点击的时候跳转进入对应的界面,但是前面的Article依然不进行改变

分别是访问Article的时候进入Article, 问Article/Articletype1的时候进入Article/Articletype1, 问Article/Articletype2的时候进入Article/Articletype2,

一级页面文章 Article.js

js
// Article.js 
import React from 'react';
import { Link, Outlet } from 'react-router-dom';

const Article = () => {
  return (
    <div>
      <h1>Article Page</h1>
      <nav>
        <Link to="Articletype1">Article Type 1</Link>{' '}
        <Link to="Articletype2">Article Type 2</Link>
      </nav>
      <Outlet />
    </div>
  );
};

export default Article;

文章类型页面组件(二级路由)

ArticleType1.js

js
// ArticleType1.js
import React from 'react';

const ArticleType1 = () => {
  return <div>Article Type 1 Page</div>;
};

export default ArticleType1;

ArticleType2.js

js
// ArticleType2.js
import React from 'react';

const ArticleType2 = () => {
  return <div>Article Type 2 Page</div>;
};

export default ArticleType2;

设置路由

导入

js
//导入
const ArticleType1 = lazy(() => import('@/views/article/Articletype1'));
const ArticleType2 = lazy(() => import('@/views/article/Articletype2'));

配置

js
//配置
 <Route path="/Article" element={<Article />}>
  <Route path="Articletype1" element={<ArticleType1 />} />
  <Route path="Articletype2" element={<ArticleType2 />} />
</Route>

接下来我们尝试一下访问Article:

点击对应的部分已经展示:

已经成功实现!

之前我们文章的跳转采用的是Link的方式,现在我们改写成为这种编程式路由的方式进行跳转

js
import { Link, Outlet,useNavigate} from 'react-router-dom';

<a href="#" onClick={(e)=>{tiao1(e)}}>Article Type 1</a>

 const tiao1=(e:any)=>{
    e.preventDefault();
    navigate('/articletype1')
 }

结果我们点击,奇怪,怎么跳转到了404 呢

其实我们正确的地址应该是 '/article/articletype1'

更改以后进行尝试:

js
  const tiao1=(e:any)=>{
    e.preventDefault();
    navigate('/article/articletype1')
  }
  const tiao2=(e:any)=>{
    e.preventDefault();
    navigate('/article/articletype2')
  }

更改方式成功!

想要的布局效果大致如下:

  • Link:Link 用于定义导航链接,但不提供样式控制。它是一个简单的 HTML <a> 标签的封装,用于在不刷新页面的情况下进行页面跳转。
  • NavLink:NavLinkLink 的增强版,它可以为当前页面匹配的链接添加活动状态(active state),通常用于设置导航链接的样式以显示当前页面或路由的状态。你可以根据路由匹配情况添加自定义的类名或样式。

需要为导航链接添加样式以反映当前页面或路由的活动状态,那么建议使用 NavLink

只是需要简单的导航链接而不需要活动状态的样式控制,使用 Link 就可。

我们文章之中使用了Link,这里我们菜单使用 NavLink

之前我们都是这么写的:

js
{/* NavLink */} 
<NavLink to="/" activeClassName="active">Home</NavLink>
<NavLink to="/about" activeClassName="active">About</NavLink>

结果在v6一写直接报错: 果然,这货在v6之中更改了写法,果然一步一个坑啊

v6版本之中路由更改成了下面的写法:

js
let activeClassName = "underline"
<NavLink
	to="/faq"
	className={({ isActive }) =>
	  isActive ? activeClassName : undefined
	}
>
  FAQs
</NavLink>

来看看匹配时候我们的路由

13、完善一下我们的路由:

js

import AntdComp from "./components/AntdComp";
import Header from "./components/Header";
import Login from "./views/Login";
import Register from "./views/Register";
import ForgetPassword from "./views/ForgetPassword";
import { Button, ConfigProvider, Space } from 'antd';
import NotFind from "./views/NotFind";
import Home from "./views/Home";
import User from "./views/subs/User";
import Role from "./views/subs/Role";
import { BrowserRouter, HashRouter, Routes, Route, Link, NavLink, Navigate } from "react-router-dom"
function App() {
 return (
   <ConfigProvider
     theme={{
       token: {
         // Seed Token,影响范围大
         colorPrimary: '#7cb305'
      },
    }}
   >
    {/* 路由器 */}
     <BrowserRouter>
      {/* 路由映射列表 */}
       <ul>
         <li>
           <Link to="/register">注册</Link>
         </li>
         <li>
           <NavLink to="/forget">忘记密码</NavLink>
         </li>
       </ul>
       <Routes>
        {/* 路由具体路径匹配 */}
         <Route path="/" element={<Navigate to="/login"></Navigate>}></Route>
         <Route path="/login" element={<Login></Login>}></Route>
         <Route path="/home" element={<Home></Home>}>
           <Route index element={<User></User>}></Route>
           <Route path="role" element={<Role></Role>}></Route>
         </Route>
         <Route path="/register" element={<Register></Register>}></Route>
         <Route path="/forget" element={<ForgetPassword></ForgetPassword>}></Route>
         <Route path="/404" element={<NotFind></NotFind>}></Route>
         <Route path="*" element={<Navigate to="/404"></Navigate>}></Route>
       </Routes>
     </BrowserRouter>
   </ConfigProvider>
);
}

export default App;

在Home下面配置路由渲染出口

js
import React from 'react'
import { Outlet, Link } from "react-router-dom"

export default function Home() {
   return (
       <div style={{ display: "flex" }}>
           <div style={{ width: "200px", backgroundColor: "pink" }}>
               <ul>
                   <li>
                       <Link to="/home/user">用户</Link>
                   </li>
                   <li>
                       <Link to="/home/role">角色</Link>
                   </li>
               </ul>
           </div>
           <div>
               <h3>content</h3>
               <Outlet></Outlet>
           </div>
       </div>
  )
}

检查一下我们的路由,完美实现!

Released under the MIT License.