✋手摸手系列(一/2): vite react typescript reactHook mobx(非脚手架)(从0开始):路由和权限搭建

885 阅读2分钟

继续上一篇:✋手摸手系列(一/1): vite react typescript reactHook mobx(非脚手架)(从0开始)(包含路由权限控制)

后台系列目录

  1. ✋手摸手系列(一/1): vite react typescript reactHook mobx(非脚手架)(从0开始)(包含路由权限控制)

  2. ✋手摸手系列(一/2): vite react typescript reactHook mobx(非脚手架)(从0开始):路由和权限搭建

  3. ✋手摸手系列(一/3): vite react typescript reactHook mobx(非脚手架)(从0开始):mobx 接入


参考资料 umi路由设计umijs.org/zh-CN/docs/…

项目地址 github.com/wowhoonet/v…

路由搭建

安装 react-route react-route-dom 依赖

yarn add react-router react-router-dom
yarn add @types/react-router @types/react-router-dom -D

在根目录创建 route>index.ts, 代码如下:

import React from "react";

/**
 * 路由文件
 */
 export interface IRoute {
  path: string;
  exact?: boolean;
  component?: React.ComponentType<any>;
  routes?: IRoute[];
  wrappers?: React.ComponentType<any>[];
  title?: string;
  redirect?: string;
  hide?: boolean;
  icon?: any;
}

export const routes: IRoute [] = [
  {
    path: '/home',
    exact: true,
    title: 'home页面',
    component: React.lazy(() => import("@/view/Home")),
  }
]

新增入口文件 view->App->index.tsx 代码如下:

import { IRoute, routes } from '@/route';
import React, { Suspense, useMemo } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import styles from './index.module.less';

export default function App (): React.ReactElement {


  const getChildrenComponent = (
    route: IRoute,
    key: number,
    pPath: string = ""
  ) => {
    const path = pPath + route.path;
    return route.redirect ? (
      <Redirect key={key} to={route.redirect} from={route.path}></Redirect>
    ) : (
      (route.component || route.routes?.length > 0) && (
        <Route key={key} path={path} exact={route.exact}>
          {route.wrappers?.length > 0
            ? route.wrappers.reduceRight(
                (element: any, wrapper: any) =>
                  React.createElement(wrapper, {}, element),
                React.createElement(
                  route.component || React.Fragment,
                  {},
                  <Switch>
                    {route?.routes?.map((croute, rindex) =>
                      getChildrenComponent(croute, rindex, path)
                    )}
                  </Switch>
                )
              )
            : React.createElement(
                route.component || React.Fragment,
                {},
                <Switch>
                  {route?.routes?.map((croute, rindex) =>
                    getChildrenComponent(croute, rindex, path)
                  )}
                </Switch>
              )}
        </Route>
      )
    );
  };

  const Routes = useMemo(() => {
    const _Routes = routes.map((route, rindex) =>
      getChildrenComponent(route, rindex)
    );
    console.log(_Routes, "_Routes");
    return _Routes;
  }, []);
  
  return <Suspense fallback={<div>加载中</div>}>
      <HashRouter basename="/">
        <Switch>{Routes}</Switch>
      </HashRouter>
  </Suspense>
}

这里需要注意的是我们的 routes 结构是个嵌套结构,所以我们需要抽出方法来实现递归,这里有个wrappers大家可以猜一下干甚用的,下面马上就要讲到了

这时候 yarn dev 跑一下, 然后访问http://localhost:3000/#/home 应该就可以看到效果了

权限控制

wrapper

译为:包装器

概念来源于 umi 的路由设计,小看了一下源码,然后加入到咱们项目中来

开整 wrapper 设计

  1. 新建 wrappers->auth.tsx
import React from 'react';
import { Redirect } from 'react-router';
import styles from './index.module.less';

export default function Auth (props: {
  children: React.ReactElement
}): React.ReactElement {
  const isLogin =  false; // 后续换成自己的 token 校验
  const {children, ...cprops} = props;
  if(isLogin) {
    return children
  }
  return <Redirect to="/login"></Redirect>;
}

大家看到这里应该知道我的用意了吧,意思是如果我登录了我就渲染我的 children,如果没有登录就重定向到 login;结合一下 route 里面的wraper代码

// xxx
route.wrappers.reduceRight(
                (element: any, wrapper: any) =>
                  React.createElement(wrapper, {}, element),
                React.createElement(
                  route.component || React.Fragment,
                  {},
                  <Switch>
                    {route?.routes?.map((croute, rindex) =>
                      getChildrenComponent(croute, rindex, path)
                    )}
                  </Switch>
                )
              )
// xxx

用 wraper 把要渲染的路由包裹起来,就起到了高阶组件的用意了,也就是拦截器的作用

现在完善一下 view->Login 路由组件和 route->index.ts 的路由内容

image.png

Run!run 跑起来

在地址栏输入 http://localhost:3000/#/home 会自动重定向到 login

总结

  1. 引入 react-router 系列包
  2. 通过递归方式生成组件,原理是通过 React.createElement生成包裹组件
  3. 通过wrapper 的方式进行路由拦截

下一篇讲 mobx,大家一起加油