路由拦截在 Vue 中有现成的 API,所以在 Vue 中实现起来并不复杂。但是 React-router 中并没有这个功能,作者的目的是为了更加的灵活,鼓励我们自己去实现这个功能。当然思路很简单,我的思路就是在每个路由组件外层包裹一层组件进行判断。
本次路由使用的是v6版本,与之前的版本有很大的改动,所以请事先去了解这些变化。
talk is cheap show me my code
首先基本目录如下:
在App.jsx中导入路由配置:
import { Link } from "react-router-dom";
import { Route, Routes, useRoutes } from "react-router-dom";
import "./App.css";
import routes from "./router";
function App(props) {
const elements = useRoutes(routes);
return (
<div className="App">
<h2>跳转</h2>
<Link to="/router1">router1</Link>|<Link to="/router2">router2</Link>
{elements}
</div>
);
}
export default App;
router.jsx内容如下:
/*
* @Date: 2022-01-23 20:15:56
* @LastEditors: zhangheng
* @LastEditTime: 2022-03-09 16:18:35
*/
import React, { lazy, Suspense, ComponentType } from "react";
import type { RouteObject } from "react-router-dom";
import Authorized from "./authorized";
import NoAuthor from "@/pages/403";
const routes: RouteObject[] = [
{
path: "/router1",
element: () => import("@/pages/router1"),
},
{
path: "/router2",
element: () => import("@/pages/router2"),
},
{
path: "/403",
element: <NoAuthor />,
},
];
type lazyPropsType = () => Promise<{ default: ComponentType }>;
interface propsType {
importRoute: lazyPropsType;
}
//定义自动包裹Suspense函数
function LazyElement(props: propsType) {
return function () {
const { importRoute } = props;
const LazyComponent = lazy(importRoute);
return (
<Suspense fallback={<div>路由懒加载...</div>}>
<LazyComponent />
</Suspense>
);
};
}
// 处理routes 如果element是懒加载,要包裹Suspense,这里还自动包了一层懒加载组件
function dealRoutes(routesArr: RouteObject[]) {
if (routesArr && Array.isArray(routesArr) && routesArr.length > 0) {
routesArr.forEach((route) => {
if (route.element && typeof route.element == "function") {
const importRoute = route.element as lazyPropsType;
route.element = (
<Authorized
component={LazyElement({ importRoute })}
include={["/router1", "/router2"]}
/>
);
}
if (route.children) {
dealRoutes(route.children);
}
});
}
}
dealRoutes(routes);
export default routes;
authorized.tsx鉴权组件,很简洁的:
/*
* @Date: 2022-03-09 11:49:30
* @LastEditors: zhangheng
* @LastEditTime: 2022-03-09 16:17:18
*/
//这里是路由拦截组件判断进入的路由是否有权限
import { memo, PropsWithChildren, ComponentType } from "react";
import { Navigate, useLocation } from "react-router-dom";
interface RediectType {
path?: string;
[key: string]: any;
}
function Rediect(props: PropsWithChildren<RediectType>) {
const { path = "/" } = props;
return <Navigate to={path} />;
}
interface AuthorizedType {
component: ComponentType;
include?: string[]; //需要鉴权的路由
}
export default memo(function Authorized(
props: PropsWithChildren<AuthorizedType>
) {
//props/state
//判断逻辑
const isToken = false;
const { component: RouteComponent, include } = props;
function returnRouteComponent(include: string[] = []) {
const location = useLocation();
if (include.includes(location.pathname)) {
//当然判断登陆了之后还可以判断用户是否有权限,这里不再补充
return isToken ? <RouteComponent /> : <Rediect path="/403" />;
} else {
return <RouteComponent />;
}
}
//redux hooks
//other hooks
//其他逻辑
return returnRouteComponent(include);
});
当然我只是简单的设置了几个配置项,所以根据项目复杂度自行进行丰富吧。