❤React-ReactRouter路由的使用
React Router 在 2021 年 11 月份的时候更新 v6 的版本,本次主要学习的也是v6,里面更改了很多新写法特性!
1、路由的认识
官网给他定义是一个库,不是一个框架。
React官方并没有提供路由库,路由插件,而是推荐我们使用React结合ReactRouter来进行路由的映射。
正常的路由开发模式分为以下三种:
- 编程式路由:自己在页面中写代码进行路由编程,包括映射、路由引入。
- 配置式路由:将路由映射写到配置文件中,剩下的就是自动渲染。
- 约定式路由:无需配置路由,你的项目文件系统就是路由。(Next就是这种方式)
先来看看Vuejs配置式路由:
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路由
yarn add react-router-dom
3、路由的使用
我们先在App.jsx 组件搭建路由(四个页面主要是后台首页、登陆页面、后台文章、后台用户)
App.jsx之中引入页面
import Home from '@/pages/Home';
import Login from '@/pages/Login';
import User from '@/pages/User';
import Article from '@/pages/Article';
App.jsx之中路由的引入和使用
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只能用一次
<Routes>
<Route path=/ index element={<Home></Home>}></Route>
</Routes>
重定向规则
import {Navigate} from react-router-dom
<Routes>
<Route path=/ element={<Navigate to=/login></Navigate>}></Route>
</Routes>
我们还可以用重定向解决404的问题
完整页面大致如下:
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 ,这个文件夹下面就专门负责我们的路由
接下来我们把路由给拿出来单独放到一文件夹里面
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
进行冲定向
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的功能
<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
const Home = lazy(() => import('@/pages/Home'));
const Login = lazy(() => import('@/pages/Login'));
const NotFind = lazy(() => import('@/pages/NotFind'));
9、使用Suspense
默认加载效果
v6之前的版本使用
// 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版本对此作了一些调整
// 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
// Article.js
import React from 'react';
import { Link, Outlet } from 'react-router-dom';
const Article = () => {
return (
<div>
Article Page
<nav>
<Link to=Articletype1>Article Type 1</Link>{' '}
<Link to=Articletype2>Article Type 2</Link>
</nav>
<Outlet />
</div>
);
};
export default Article;
文章类型页面组件(二级路由)
ArticleType1.js
// ArticleType1.js
import React from 'react';
const ArticleType1 = () => {
return <div>Article Type 1 Page</div>;
};
export default ArticleType1;
ArticleType2.js
// ArticleType2.js
import React from 'react';
const ArticleType2 = () => {
return <div>Article Type 2 Page</div>;
};
export default ArticleType2;
设置路由
导入
//导入
const ArticleType1 = lazy(() => import('@/views/article/Articletype1'));
const ArticleType2 = lazy(() => import('@/views/article/Articletype2'));
配置
//配置
<Route path=/Article element={<Article />}>
<Route path=Articletype1 element={<ArticleType1 />} />
<Route path=Articletype2 element={<ArticleType2 />} />
</Route>
接下来我们尝试一下访问Article:
点击对应的部分已经展示:
已经成功实现!
11、Link 改成编程式路由的方式进行跳转
之前我们文章的跳转采用的是Link的方式,现在我们改写成为这种编程式路由的方式进行跳转
import { Link, Outlet,useNavigate} from 'react-router-dom';
<a rel=nofollow href=# onClick={(e)=>{tiao1(e)}}>Article Type 1</a>
const tiao1=(e:any)=>{
e.preventDefault();
navigate('/articletype1')
}
结果我们点击,奇怪,怎么跳转到了404 呢
其实我们正确的地址应该是 '/article/articletype1'
更改以后进行尝试:
const tiao1=(e:any)=>{
e.preventDefault();
navigate('/article/articletype1')
}
const tiao2=(e:any)=>{
e.preventDefault();
navigate('/article/articletype2')
}
更改方式成功!
12、接下来在我们的后台实现一下管理部分的二级菜单效果admin(NavLink
和 Link
)
想要的布局效果大致如下:
- Link:
Link
用于定义导航链接,但不提供样式控制。它是一个简单的 HTML<a>
标签的封装,用于在不刷新页面的情况下进行页面跳转。 - NavLink:
NavLink
是Link
的增强版,它可以为当前页面匹配的链接添加活动状态(active state),通常用于设置导航链接的样式以显示当前页面或路由的状态。你可以根据路由匹配情况添加自定义的类名或样式。
需要为导航链接添加样式以反映当前页面或路由的活动状态,那么建议使用 NavLink
。
只是需要简单的导航链接而不需要活动状态的样式控制,使用 Link
就可。
我们文章之中使用了Link,这里我们菜单使用 NavLink
之前我们都是这么写的:
{/* NavLink */}
<NavLink to=/ activeClassName=active>Home</NavLink>
<NavLink to=/about activeClassName=active>About</NavLink>
结果在v6一写直接报错: 果然,这货在v6之中更改了写法,果然一步一个坑啊
v6版本之中路由更改成了下面的写法:
let activeClassName = underline
<NavLink
to=/faq
className={({ isActive }) =>
isActive ? activeClassName : undefined
}
>
FAQs
</NavLink>
来看看匹配时候我们的路由
13、完善一下我们的路由:
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下面配置路由渲染出口
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>
)
}
检查一下我们的路由,完美实现!