您现在的位置是:首页 > 正文

react-router-dom v6.5.0实现路由守卫RouterBeforeEach及缓存

2024-02-01 04:45:58阅读 3

一、概述

        最近留意下react-router-dom有更新到6.6.1的版本,在这个版本增加了不少的功能。研究了下,可以利用其提供的API实现一个类似Vue的路由守卫,从而简便达到路由鉴权的业务场景。这里我是使用npm的包,是react-router-dom v6.5.0,但是基本新增的功能都有。

Github:码源

react-router-dom官网

二、createHashRouter

        这个函数可以帮助我们,采用编程的方式生成一个路由。

import { createHashRouter,useRouteError,redirect} from "react-router-dom";
import { Suspense, lazy } from 'react'
import React from "react";
import KeepAlive from 'react-activation'

type IRouterBeforeLoad = (res:any, redirectUrl: string) => Boolean;
let routerLoader: IRouterBeforeLoad;
let _redirectUrl: string = "/";
const routes = [
  {
    path: '/',
    auth: false,
    name:"login",
    component:lazy(() => import('@/page/login/login'))
  },
  {
    path: '/Portal',
    name:"Portal",
    component:lazy(() => import('@/page/portal/portal')),
    children: [
      { 
        path: '/Portal/Home',
        name:"Home",
        component:lazy(() => import('@/page/home/home'))
      },
      { 
        path: '/Portal/Lifecycle',
        name:"Lifecycle",
        component:lazy(() => import('@/page/lifecycle/lifecycle'))
      },
      { 
        path: '/Portal/NotFound',
        name:"NotFound",
        component:lazy(() => import('@/page/error/NotFound'))
      },
      { 
        path: '*',
        component:lazy(() => import('../page/error/NotFound'))
      },
    ]
  },
  { 
    path: '*',
    component:lazy(() => import('../page/error/NotFound'))
  },
]


function ErrorBoundary() {
  let error:any = useRouteError();
  return <div>
    <div>{ error.message}</div>
    <div>{ error.stack}</div>
  </div>;
  return <></>
}

// 路由处理方式
const generateRouter = (routers:any) => {
  return routers.map((item:any) => {
    if (item.children) {
      item.children = generateRouter(item.children)
    }
    item.element = <Suspense fallback={
      <div>加载中...</div>
    }>
      {/* 把懒加载的异步路由变成组件装载进去 */}
      <KeepAlive id={item.name} cacheKey={item.name}>
        <item.component />
      </KeepAlive>
    </Suspense>
    item.errorElement = <ErrorBoundary></ErrorBoundary>
    item.loader = async (res: any) => {
      if (routerLoader && !item.children) {
        if (routerLoader(res,_redirectUrl)) {
          return res;
        } else { 
          return redirect(_redirectUrl);
        }
      }
      return res;
    }
    return item
  })
}

const RouterLoader = (fun: IRouterBeforeLoad) => {
  routerLoader = fun;
}

const Router  = ()=>createHashRouter(generateRouter([...routes]))
export{ Router,RouterLoader}

三、errorElement、useRouteError

        路由中errorElement属性是新加的,其接受一个组件,在当前路由组件有错误的时候显示。但是这个功能和缓存组件<KeepAlive>组件有冲突。也就是目前使用缓存后,这个错误组件无法正常使用。可以留意下react-activation作者后续有没有修正这个bug。

        useRouteError这个hook是新增的,用于获取组件的报错信息。这里两个功能结合使用可以使错误信息自定义展示在页面,避免组件出错后,整个系统页面白屏。

 四、redirect

        重定向钩子,是目前官方提供的唯一一个非hook控制路由的钩子,其可以再纯js函数中使用,重新向路由。

五、自定义跳转hook,实现路由守卫RouterBeforeEach

        官方提供的路由跳转是使用useNavigate hook的,这里我们要实现路由守卫,那么我需要在路由跳转前做逻辑的判断,所以我自定义了一个useUtilsNavigate hook用于跳转前的判断。只要是通过这个hook跳转的路由都可以响应到路由守卫。

import { NavigateFunction, Location, To, NavigateOptions } from "react-router-dom";
import { RouterLoader } from "@/routes/route";
type IrouterBeforeLoad = (to:Ito,location?: Location) => Boolean;

interface Ito {
  to: To, options?: NavigateOptions
 }

let routerBeforeLoad: IrouterBeforeLoad;
let flag: Boolean = true;

const RouterBeforeEach = (fun: IrouterBeforeLoad) => {
  ///页面刷新时,配合loader实现调用,并做拦截重定向,由flag判断是否是初次刷新页面,以免在useUtilsNavigate调用是触发多次路由校验
  RouterLoader((res: any,redirectUrl:string) => { 
    let result: Boolean=true;
    if (flag) { 
      let url = new URL(res.request.url)
      result = fun({ to: url.pathname })
      if (redirectUrl==url.pathname) { 
        result = true;
      }
    }
    return result;
  })
  routerBeforeLoad = fun;
}

///所有的js路由跳转通过此函数,由此做路由拦截
const useUtilsNavigate=(navigate:NavigateFunction,location:Location,to: To, options?: NavigateOptions)=>{
  if (routerBeforeLoad && routerBeforeLoad({ to, options }, location)) {
    //flag设置false标志已经不是第一次加载页面
    flag = false;
    navigate(to, options)
  } else {
    return;
  }
  //flag设置false标志已经不是第一次加载页面
  flag = false;
  navigate(to,options)
}

export { useUtilsNavigate, RouterBeforeEach };
export type { IrouterBeforeLoad,Ito };

RouterLoader这个函数钩子是在路由定义的文件里面导出的,可以看到在route.tsx,其在loader属性里面被调用。loader这个也是新版本提供的一个新功能,其会在组件页面加载时先回调这个钩子,我在这里根据flag判断是否页面初始加载。因为页面通过URL直接打开的话,是没有经过useUtilsNavigate,也就是无法通过它去做路由监听,所以需要使用loader这个钩子,在初次加载时,触发路由守卫。

六、在程序主入口注册路由守卫钩子

import ReactDOM from 'react-dom';
import {RouterProvider } from "react-router-dom";
import './index.css'
import { Router } from './routes/route';
import { AliveScope } from 'react-activation'
import React from 'react';
import { RouterBeforeEach } from "@/utils/useUtilsNavigate";
RouterBeforeEach(( to,from) => { 
  console.log("路由守卫to", to)
  console.log("路由守卫from", from)
  return true;
})

ReactDOM.render(
    <AliveScope>
      <RouterProvider router={Router()}/>
    </AliveScope>,
  document.getElementById('root')
);

网站文章

  • Java中抽象类和接口

    一.抽象类  在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为: 1 abstract void fun();   抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法...

    2024-02-01 04:45:53
  • Grafana任意文件读取 (CVE-2021-43798)

    Grafana任意文件读取 (CVE-2021-43798)

    Grafana是一个跨平台、开源的数据可视化网络应用程序平台。用户配置连接的数据源之后,Grafana可以在网络浏览器里显示数据图表和警告。Grafana 存在未授权任意文件读取漏洞,攻击者在未经身份验证的情况下可通过该漏洞读取主机上的任意文件。

    2024-02-01 04:45:25
  • dubbox在异构系统中的使用-补充1

    除了添加必要的dependencies外,其他需要设置的文件包括:1. web.xml,加载dubbox dispatch servlet:&lt;?xml version=&quot;1.0&quo...

    2024-02-01 04:45:19
  • Android 8.0 App Standby

    一、概述低电耗模式和应用待机模式是从Android M引入的新特性,之前一直没有分析,低电耗模式就是Doze,应用待机模式就是 App Standby。Doze模式我们之前分析过了,Doze模式在Android N又有修改,Android 6.0(API 级别 23)引入了低电耗模式,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟 CPU 和网络活动,从而延长电池寿命。而 A...

    2024-02-01 04:45:01
  • 维宏控制卡win7 驱动_雕刻机专用维宏5.55运动驱动控制卡

    详情介绍雕刻机维宏控制卡电脑雕刻机控制系统功能特点: 1.全中文windows界面,图形三维显示,操作简捷; 2.pci总线插卡结构,pci 2.1标准,windows 2000/nt/98兼容; 3...

    2024-02-01 04:44:52
  • Vue3 计算属性

    Vue3 计算属性

    上一篇博文说了 vue3 项目的 toRefs 函数和 toRef 函数,今天就稍微总结一下 vue3 的计算属性,其实学过 vue2 的宝子们应该都清楚,计算属性这个东西在项目开发过程中使用的还是比...

    2024-02-01 04:44:25
  • Spring data elasticsearch简单上手 | ES-7版本,springboot 2.4

    本来觉得写这个没什么意义,感觉看看别人就够了,然鹅,,,,被网上的坑的很惨再次强调本文的环境:2021年1月23日01:51:43的最新配置spring boot 2.4版本Elasticsearch...

    2024-02-01 04:44:18
  • Typora 开始收费,改用好玩的MarkText

    Typora 开始收费,改用好玩的MarkText

    收费……可以考虑使用:MarkText简述MarkTextMarkText 这个工具侧重于“命令”,导航栏都被收起来了。有些小伙伴感觉反而不好用,其实不然,是未了解该工具的强大之处。md 文本本身就是...

    2024-02-01 04:44:12
  • jsp中base标签的两种使用方法

    方法一 &lt;% String basePath = request.getScheme() + &quot;://&quot; + request.getServerName() + &quot;...

    2024-02-01 04:43:41
  • Cython入门到放弃(一) 热门推荐

    无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。教程链接:https://www.cbedai.net/qtlyx python作为一门强大的脚本语言,优势自然不必说,目前中低频的量化投资基本都是使用python作为research和production作为语...

    2024-02-01 04:43:33