reactrouter4路由钩子_React Router 4.0 实现路由守卫

在使用 Vue 或者 Angular 的时候,框架提供了路由守卫功能,用来在进入某个路有前进行一些校验工作,如果校验失败,就跳转到 404 或者登陆页面,比如 Vue 中的 beforeEnter 函数:

...

router.beforeEach(async(to, from, next) => {

const toPath = to.path;

const fromPath = from.path;

})

...

在之前的版本中,React Router 也提供了类似的 onEnter 钩子,但在 React Router 4.0 版本中,取消了这个方法。React Router 4.0 采用了声明式的组件,路由即组件,要实现路由守卫功能,就得我们自己去写了。

如果不使用路由守卫,Router 组件是这样子的:

import * as React from 'react';

import { HashRouter,Switch,Route,Redirect } from 'react-router-dom';

import { HomePage } from '../pages/home/home.page';

import { LoginPage } from '../pages/login/login.page';

import { ErrorPage } from '../pages/error/error.page';

export const Router = () => (

);

上面的 Router 组件,包含了三个页面:

登陆

主页

404 页面

以及四个路由:

根路由

登陆路由

主页路由

404 路由

其中,根路由和 /home 路由,都定向到了主页路由。

以上是一个基本的路由定义,可以在登陆/主页和 404 页面之间来回跳转,但也有一些问题:

非登陆状态下,可以直接跳转到主页

登陆状态下,也可以输入 /login 路由跳转到登录页

现在,我们想完成这样的功能:

非登陆状态下,无法直接跳转到主页,如果在非登陆状态下进行主页跳转,需要重定向至登陆路由

登陆状态下,无法跳转至登录页,如果在登陆状态下进行登陆页跳转,需要重定向至主页路由

要完成这个功能,有两种方案:

在每个组件中,根据 props 上的 history 对象来进行跳转

进行全局的路由守卫处理

第一种方式,实现起来比较简单,但有很多的代码量,这里主要介绍第二种方式。

在 React Router 4.0 中,没有再像之前的版本那样,提供 onEnter 这样的全局跳转钩子,因此要通过高阶组件的方式去处理。

下面是我的实现方式,首先,准备一份路由表,包含了路由的地址,组件以及是否需要权限校验:

import { HomePage } from '../pages/home/home.page';

import { LoginPage } from '../pages/login/login.page';

import { ErrorPage } from '../pages/error/error.page';

interface routerConfigModel {

path:string,

component?:any,

auth?:boolean

}

export const routerConfig:routerConfigModel[] = [

{

path:'/',

component:HomePage,

auth:true,

},{

path:'/home',

component:HomePage,

auth:true,

},{

path:'/login',

component:LoginPage,

},{

path:'/404',

component:ErrorPage

}

];

将 auth 设置为 true,表示该路由需要权限校验。

然后,定义 Router 组件,该组件是经过高阶组件包装后的结果:

import * as React from 'react';

import { HashRouter,Switch } from 'react-router-dom';

import { FrontendAuth } from '../components/frontend-auth/frontend-auth.component'

import { routerConfig } from './router.config'

export class Router extends React.Component{

render(){

return(

);

}

}

所有的路由跳转,都交给 FrontendAuth 高阶组件代理完成。下面是 FrontendAuth 组件的实现:

import * as React from 'react';

import { Route,Redirect } from 'react-router-dom';

import { propsModel } from './frontend-auth.model'

export class FrontendAuth extends React.Component{

render(){

const { location,config } = this.props;

const { pathname } = location;

const isLogin = localStorage.getItem('__config_center_token')

// 如果该路由不用进行权限校验,登录状态下登陆页除外

// 因为登陆后,无法跳转到登陆页

// 这部分代码,是为了在非登陆状态下,访问不需要权限校验的路由

const targetRouterConfig = config.find((v:any) => v.path === pathname);

if(targetRouterConfig && !targetRouterConfig.auth && !isLogin){

const { component } = targetRouterConfig;

return

}

if(isLogin){

// 如果是登陆状态,想要跳转到登陆,重定向到主页

if(pathname === '/login'){

return

}else{

// 如果路由合法,就跳转到相应的路由

if(targetRouterConfig){

return

}else{

// 如果路由不合法,重定向到 404 页面

return

}

}

}else{

// 非登陆状态下,当路由合法时且需要权限校验时,跳转到登陆页面,要求登陆

if(targetRouterConfig && targetRouterConfig.auth){

return

}else{

// 非登陆状态下,路由不合法时,重定向至 404

return

}

}

}

}

以及对应的 Model:

export interface propsModel {

config:any[],

}

页面上的路由跳转,都由 FrontendAuth 高阶组件代理了,在 Switch 组件内部,不再是 Route 组件,而只有一个 FrontendAuth 组件。

FrontendAuth 组件接收一个名为 config 的 Props,这是一份路由表。同时,由于 FrontendAuth 组件放在了 Switch 组件内部,React Router 还自动为 FrontendAuth 注入了 location 属性,当地址栏的路由发生变化时,就会触发 location 属性对象上的 pathname 属性发生变化,从而触发 FrontendAuth 的更新(调用 render 函数)。

FrontendAuth 的 render 函数中,根据 pathname 查找到路由表中的相关配置,如果该配置中指定了无需校验,就直接返回相应的 Route 组件。

如果查找到的配置需要进行校验,再根据是否登陆进行处理,具体可以查看代码中的注释。

总结一下,实现路由守卫需要考虑到以下的问题:

未登录情况下,访问不需要权限校验的合法页面:允许访问

登陆情况下,访问登陆页面:禁止访问,跳转至主页

登陆情况下,访问除登陆页以外的合法页面:允许访问

登陆情况下,访问所有的非法页面:禁止访问,跳转至 404

未登录情况下,访问需要权限校验的页面:禁止访问,跳转至登陆页

未登录情况下,访问所有的非法页面:禁止访问,跳转至 404

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值