路由拦截在 Vue 中有现成的 API,所以在 Vue 中实现起来并不复杂。但是 React-router 中并没有这个功能,作者的目的是为了更加的灵活,鼓励我们自己去实现这个功能。当然思路很简单,我的思路就是在每个路由组件外层包裹一层组件进行判断。

本次路由使用的是v6版本,与之前的版本有很大的改动,所以请事先去了解这些变化。

talk is cheap show me my code

首先基本目录如下:
image.png

在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);
});

当然我只是简单的设置了几个配置项,所以根据项目复杂度自行进行丰富吧。

Last modification:March 9, 2022
如果觉得我的文章对你有用,请随意赞赏