react|react-router 5 管理路由

实现功能: + 全局路由统一管理,支持配置路由重定向、路由懒加载、自定义meta字段等。 + 全局路由拦截,支持读取路由meta配置,支持拦截跳转其他路由等。依赖版本: + `react@17.0.2` + `react-router-dom@5.3.0` // react-router v5

一、react路由 react-router-dom v5版本里,路由不再是js,而是一个个组件,即
通过path路径区分不同的路由来渲染。配合组件只渲染内部第一个匹配到的这个特性,来实现不同的路由地址显示对应不同的页面。
基础结构大概长这样:
>

二、路由统一管理 要实现路由的统一管理,类似vue-router那样配置一个js数组来管理路由,就要考虑写一个方法来根据路由配置数组来自动生成对应的jsx dom结构。
react-router-config插件来之前能实现类似的效果,但插件已经很久没更新了,而且插件不支持路由懒加载,所以考虑手写实现。
1、路由配置文件
项目src/router/index.js里填写路由配置:
import { lazy } from 'react'export const routes = [ { path: '/', redirect: '/index', // 路由重定向字段 }, { path: '/index', component: lazy(() => import(/* webpackChunkName: "index" */ '@/views/index/index')), meta: { // meta字段用来自定义路由配置 title: '首页', }, }, { path: '/login', component: lazy(() => import(/* webpackChunkName: "login" */ '@/views/login/index')), meta: { title: '登录', }, }, { path: '*', component: lazy(() => import(/* webpackChunkName: "404" */ '@/views/test/page404')), meta: { title: '404', }, }, ]

2、封装路由组件
项目src/components/GlobalRouter/index.jsx里封装组件引入路由配置:
import { BrowserRouter, Switch } from 'react-router-dom' import { Suspense } from 'react' import RouterList from './routerList'function GlobalRouter ({ routes }) { return ( ={
{/* loading */}
}> >
) }export default GlobalRouter

项目src/components/GlobalRouter/routerList.jsx里封装组件渲染路由列表:
import { Route, Redirect } from 'react-router-dom'function routerList ({ routes, location }) { const { pathname } = locationconst route404 = routes.find(v => v.path === '*') || {} const currentRoute = routes.find(v => v.path === pathname) || route404return currentRoute.redirect ? () : () }export default routerList

  • 这里之所以又封装了一个routerList.jsx组件是利用了这个组件在包裹下能够通过props获取当前访问的路由location对象,后续就能依此做处理。
  • 路由全部为精确匹配。
3、引入路由组件
项目入口文件src/index.js(或根组件App.js)里配置引入封装好的组件:
import { StrictMode } from 'react' import ReactDOM from 'react-dom' import GlobalRouter from '@/components/GlobalRouter' import { routes } from '@/router'ReactDOM.render( > , document.getElementById('root') )

这样就实现了基本的路由统一管理配置。
PS:
  • 我这里是使用的路由history模式,如果是路由hash模式就把BrowserRouter替换成HashRouter。
  • 如果项目是部署在服务器域名的子目录下,就给BrowserRouter添加basename属性,值为子目录路径,例如/h5。
三、全局路由拦截 实现路由全局拦截,来自定义一些判断处理,类似vue里的beforeEach钩子函数,这里就在上述封装好的文件里作修改。
1、路由拦截函数
项目src/router/index.js里添加内容:
/** * @description: 全局路由拦截 * @param {object} route 当前路由配置对象 * @return {string} 需要重定向到其他页时返回该页的path路径 */ export function onRouterBefore (route) { const meta = route.meta || {}// 示例:动态修改页面title if (meta.title !== undefined) { document.title = meta.title }// 示例:未登录时跳转登录页 if (!isLogin) { return '/login' } }

  • 这里定的规则就是如果需要拦截跳转其他页,onRouterBefore就return一个返回值,值为要跳转的页面path路径,不需要跳转就不用return。
2、处理拦截函数
项目src/components/GlobalRouter/routerList.jsx里修改内容:
function routerList ({ routes, location, onRouterBefore }) { const { pathname } = locationconst route404 = routes.find(v => v.path === '*') || {} const currentRoute = routes.find(v => v.path === pathname) || route404const resultPath = onRouterBefore && onRouterBefore(currentRoute) if (resultPath && resultPath !== pathname) { return } else { return currentRoute.redirect ? () : () } }

  • 拦截跳转其他页面时都是采用的重定向跳转方式。
项目src/components/GlobalRouter/index.jsx里接收onRouterBefore:
function GlobalRouter ({ routes, onRouterBefore }) { return ( ={
{/* loading */}
}> >
) }

项目入口文件src/index.js里传入onRouterBefore:
import { routes, onRouterBefore } from '@/router'ReactDOM.render( > , document.getElementById('root') )

这样全局路由拦截方案就大概完成了。
四、思考 1、插件化处理
  • 配置文件都在src/router文件夹里;
  • 实现逻辑都在src/components/GlobalRouter组件文件夹里;
  • 配置文件与实现逻辑的解耦,方便用于多项目共享。
2、待优化点
  • 暂未支持嵌套路由。
目前项目中已不再使用此方案,推荐另一更完整的解决方案:react-router v6 路由统一管理及路由拦截方案
【react|react-router 5 管理路由】参考链接:https://www.freesion.com/article/2728789511/

    推荐阅读