react-router-config 使用与路由鉴权

react-router-config

Static route config helpers

github: react-router-config

使用

需要注意的是,在page2中, renderRoutes(routes)的routes是在props中获取的,即应该写成renderRoutes(props.route.routes)

import React from "react";
import { renderRoutes } from "react-router-config";
import { HashRouter, Redirect } from "react-router-dom";

const routes = [
  { path: "/", exact: true, render: () => <Redirect to={"/page1"} /> },
  { path: "/page1", component: Page1 },
  {
    path: "/page2",
    component: Page2,
    routes: [
      {
        path: "/page2/child",
        component: Child
      }
    ]
  }
];

function App() {
  return (
    <HashRouter>
      <div className="App">
        <h1>Hello</h1>
        {renderRoutes(routes)}
      </div>
    </HashRouter>
  );
}

renderRoutes源码

其实就是把routes做了个map。

根据源码,就很容易做个类似vue的路由守卫了。

import React from "react";
import { Switch, Route } from "react-router";

function renderRoutes(routes, extraProps = {}, switchProps = {}) {
  return routes ? (
    <Switch {...switchProps}>
      {routes.map((route, i) => (
        <Route
          key={route.key || i}
          path={route.path}
          exact={route.exact}
          strict={route.strict}
          render={props =>
            route.render ? (
              route.render({ ...props, ...extraProps, route: route })
            ) : (
              <route.component {...props} {...extraProps} route={route} />
            )
          }
        />
      ))}
    </Switch>
  ) : null;
}

export default renderRoutes;

路由鉴权

以下是个人重写,添加了多重权限验证以及多重路由匹配(即添加渲染非<Switch>包裹的<Route>)。

export interface IRouteConfig extends RouteConfig {
  auth?: number;
  routes?: IRouteConfig[];
  multipleRoutes?: IRouteConfig[];
}

/**
 * 将路由配置渲染成节点
 * @param routes switch路由列表
 * @param authed 当前账号权限
 * @param multipleRoutes 非switch路由列表,将会在Switch节点前渲染Route
 * @param extraProps 添加额外的Route props
 * @param switchProps Switch props
 */
function renderRoutes(
  routes: IRouteConfig[] | undefined,
  authed: number,
  multipleRoutes?: IRouteConfig[],
  extraProps?: any,
  switchProps?: SwitchProps
) {
  const isMobile = checkMobile();
  let list = [];
  const mapFunc = (R: IRouteConfig[]) =>
    R.map((route, i) => (
      <Route
        key={route.key || i}
        path={route.path}
        exact={route.exact}
        strict={route.strict}
        render={props => {
          // 将authed赋值到route,试子组件可以通过route.authed获取当前用户权限
          if (authed !== undefined) route.authed = authed;
          // 不存在authed或者authed大于当前路由权限,即可渲染组件,否则跳转登录界面
          if (!route.auth || route.auth <= authed) {
            return route.render
              ? route.render({ ...props, ...extraProps, route: route })
              : route.component && (
                  <route.component {...props} {...extraProps} route={route} />
                );
          } else {
            message.warn("请先登录!");
            return (
              <Redirect to={route.auth <= 1 "/user/loginRegister/login"} />
            );
          }
        }}
      />
    ));
  if (routes) {
    list.push(
      <Switch {...switchProps} key="biubiubiu~~">
        {mapFunc(routes)}
      </Switch>
    );
    // 将非Switch包裹的Route挂载到Switch节点之前
    multipleRoutes && list.unshift(...mapFunc(multipleRoutes));
    // 返回一个数组,[<Route/>,...,<Route/>,<Switch>...</Switch>](实际元素并非如此结构,此处仅为方便说明写的伪代码),React会将数组渲染成节点
    return list;
  }
}

修改后的routes,当匹配到"/user/all/article/(id值)"的路径,页面会同时渲染Article以及All两个组件,未登录则渲染Article和Login组件,mutipleRoutes主要是为了能通过多重匹配路由模拟VUE的keep-alive效果。代码如下👇:

export const mobileRouterList: IRouteConfig[] = [
  {
    path: "/",
    exact: true,
    render: () => <Redirect to="/user/all" />
  },
  {
    path: "/user",
    component: MobileMain,
    multipleRoutes: [
      { path: "/user/:page/article/:id", component: Article }
    ],
    routes: [
      {
        path: "/user/all",
        component: lazy(() => import("@/pages/user/All"))
      },
      {
        path: "/user/me",
        auth: 1, // 用户权限必须 >=1 才可以访问
        component: lazy(() => import("@/pages/user/Me"))
      },
      {
        path: "/admin/controlPanel",
        auth: 2, // 用户权限必须 >=2(管理员) 才可以访问
        component: lazy(() => import("@/pages/admin/ControlPanel"))
      }
    ]
  }
]

修改后的rednerRoutes使用,后面参数选填:

// 顶层使用路由渲染,手动添加第二参数
renderRoutes(routes,user.authed)
// 子层组件路由渲染
renderRoutes(props.route.routes,<props.route.authed>,<props.route.multipleRoutes>,...)
阅读 2.4k

推荐阅读
切图仔的笔记
用户专栏

文章转移至掘金了,文章不再更新,掘金ID:Y-qwq

2 人关注
19 篇文章
专栏主页
目录