react-router 5 管理路由

2023-11-08

实现功能:
+ 全局路由统一管理,支持配置路由重定向、路由懒加载、自定义meta字段等。
+ 全局路由拦截,支持读取路由meta配置,支持拦截跳转其他路由等。

依赖版本:
+ `react@17.0.2`
+ `react-router-dom@5.3.0` // react-router v5

一、react路由

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

<Switch>
	<Route path="/index" />
	<Route path="/test" />
	<Route path="/demo" />
</Switch>

二、路由统一管理

要实现路由的统一管理,类似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 (
    <BrowserRouter>
      <Suspense fallback={<div>{/* loading */}</div>}>
        <Switch>
          <RouterList routes={routes} />
        </Switch>
      </Suspense>
    </BrowserRouter>
  )
}

export default GlobalRouter

项目src/components/GlobalRouter/routerList.jsx里封装组件渲染路由列表:

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

function routerList ({ routes, location }) {
  const { pathname } = location

  const route404 = routes.find(v => v.path === '*') || {}
  const currentRoute = routes.find(v => v.path === pathname) || route404

  return currentRoute.redirect
    ? (<Redirect to={currentRoute.redirect} />)
    : (<Route exact {...currentRoute} />)
}

export default routerList
  • 这里之所以又封装了一个routerList.jsx组件是利用了这个组件在<Switch>包裹下能够通过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(
  <StrictMode>
    <GlobalRouter routes={routes} />
  </StrictMode>,
  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 } = location

  const route404 = routes.find(v => v.path === '*') || {}
  const currentRoute = routes.find(v => v.path === pathname) || route404

  const resultPath = onRouterBefore && onRouterBefore(currentRoute)
  if (resultPath && resultPath !== pathname) {
    return <Redirect to={resultPath} />
  } else {
    return currentRoute.redirect
      ? (<Redirect to={currentRoute.redirect} />)
      : (<Route exact {...currentRoute} />)
  }
}
  • 拦截跳转其他页面时都是采用的重定向跳转方式。

项目src/components/GlobalRouter/index.jsx里接收onRouterBefore:

function GlobalRouter ({ routes, onRouterBefore }) {
  return (
    <BrowserRouter basename={process.env.PUBLIC_URL}>
      <Suspense fallback={<div>{/* loading */}</div>}>
        <Switch>
          <RouterList routes={routes} onRouterBefore={onRouterBefore} />
        </Switch>
      </Suspense>
    </BrowserRouter>
  )
}

项目入口文件src/index.js里传入onRouterBefore:

import { routes, onRouterBefore } from '@/router'

ReactDOM.render(
  <StrictMode>
    <GlobalRouter routes={routes} onRouterBefore={onRouterBefore} />
  </StrictMode>,
  document.getElementById('root')
)

这样全局路由拦截方案就大概完成了。

四、思考

1、插件化处理

  • 配置文件都在src/router文件夹里;
  • 实现逻辑都在src/components/GlobalRouter组件文件夹里;
  • 配置文件与实现逻辑的解耦,方便用于多项目共享。

2、待优化点

  • 暂未支持嵌套路由。

目前项目中已不再使用此方案,推荐另一更完整的解决方案:react-router v6 路由统一管理及路由拦截方案


参考链接:https://www.freesion.com/article/2728789511/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

react-router 5 管理路由 的相关文章

随机推荐

  • Navicat连接MySQL时弹出:1045:Access denied for user ‘root’@’localhost’

    错误原因 当登录MySQL数据库出现 Error 1045 错误时 表明你输入的用户名或密码错误被拒绝访问了 也可能是你的账号不允许从远程登录 只能在localhost本地登录数据库 解决办法如下 用管理员权限打开cmd 并且cd进入mys
  • 点云读取加速c++ ASCii 模式ply 或者txt

    相较于Qt Qtextstream的性能提升十倍 本文点云格式特殊 有需要自行修改即可 QFile dataFile fileName bool ret dataFile open QIODevice ReadOnly QIODevice
  • 浅谈JS的微任务和宏任务(附加面试题)

    Event Loop 因为JS是单线程 就是说 同一个时间只能做一件事 为了协调事件 用户交互 脚本 UI 渲染和网络处理等行为 防止主线程的不阻塞 Event Loop 的方案应用而生 掌握知识点 JS分为同步任务和异步任务 同步任务都在
  • (C语言)指针初识(1)——指针概念及指针类型

    指针 看似是一个令人头疼的问题 静下心来慢慢学习 指针这个主题 分成了几个的板块 比较多 耐心看完 一定会有收获啦 慢慢来 总是需要一个循序渐进的过程 目录 一 什么是指针 二 指针和指针类型 指针类型的意义 结论1 结论2 一 什么是指针
  • vue 和 react的对比

    vue 比react的优缺点 对比1 github 全球开发者星星点赞数量 此数据结果摘取于 2021年3月份 结论 vue 胜出 尤雨溪一个人撑起一个生态 战胜高手林立的巨头公司facebook 相当的传奇 对比2 React VS Vu
  • easyrecovery2023永久免费版激活密钥,手把手教您用EasyRecovery快速恢复数据

    Ontrack EasyRecovery Crack Professional是一个全面的备份和恢复实用程序 可以从多个数据丢失事件中恢复文件 例如常见的意外删除 更严重的 有时是病毒引起的 分区或驱动器格式化 甚至硬盘严重损坏后的数据丢失
  • 阿里Java代码规范

    代码规范 一 编程规约 一 命名风格 二 常量定义 三 代码格式 四 OOP 规约 五 集合处理 六 并发处理 七 控制语句 八 注释规约 九 其它 二 异常日志 一 异常处理 二 日志规约 三 单元测试 四 安全规约 五 MySQL 数据
  • YAML用法详解

    1 简介 YAML YAML Ain t Markup Language j m l 设计目标是方便人类读写 它实质上是一种通用的数据串行化格式 远比 JSON 格式方便 1 1 它的基本语法规则如下 大小写敏感 使用缩进表示层级关系 缩进
  • Spring Cloud之LB-Ribbon调用流程和源码分析(二)

    接着上面的一篇关于Spring Cloud之Open Feign调用流程和源码分析 解析feign在rpc调用的时候lb的组成及底层工作流程 关键组件介绍 ServerList 可以响应客户端的特定服务的服务器列表 ServerListFi
  • python多进程multiprocessing使用,看这篇就够了(二)

    1 上篇都是直接创建Process对象来创建子进程 其实还可以通过继承来创建子进程 来看看Process源码 可以通过承继Process 重写run方法来启动子进程 因为对一个不包括target属性 即当target None时 的Proc
  • C语言栈与队列知识,C语言数据结构基础学习笔记——栈和队列

    之前我们学过了普通的线性表 接下来我们来了解一下两种特殊的线性表 栈和队列 栈是只允许在一端进行插入或删除的线性表 栈的顺序存储结构也叫作顺序栈 对于栈顶指针top 当栈为空栈时 top 1 当栈为满栈时 top MaxSize 1 顺序栈
  • html当鼠标离开时触发事件,html中在鼠标指针移动到元素外时触发的事件属性onmouseout...

    实例 当鼠标指针移动到图像之外时执行一段 JavaScript 浏览器支持 IE Firefox Chrome Safari Opera 所有主流浏览器都支持 onmouseout 属性 定义和用法 onmouseout 属性在鼠标指针移动
  • C++实现——任意进制之间的转换

    include
  • 独孤九剑第七式-物以类聚 人以群分(K-means模型)

    文章适合于所有的相关人士进行学习 各位看官看完了之后不要立刻转身呀 期待三连关注小小博主加收藏 小小博主回关快 会给你意想不到的惊喜呀 各位老板动动小手给小弟点赞收藏一下 多多支持是我更新得动力 文章目录 前言 K means模型讲解 K
  • sparkstreaming读取文件读取不到数据

    今天用了下sparkstreaming读取hdfs文件或本地目录文件 发现文件内容一直不会被处理 使用了下面两种方法都不行 阅读源码并开启DEBUG后发现 textFileStream后面也是调用fileStream方法 并且newFile
  • make时遇到File `Makefile' has modification time 4e+04 s in the future的解决办法

    1 原因 是虚拟机时间和电脑时间不匹配造成 2 解决办法 在VMware 菜单虚拟机 M gt 设置 S gt 选项下设置开启时间同步 然后重启虚拟机 3 若还出现 warning Clock skew detected Your buil
  • 对Unity中的欧拉角的理解

    前言 欧拉角对人来说是十分直观的 很适合人机交互中 但不适用于插值和迭代 在说到欧拉角时有两点非常重要 旋转方式和旋转顺序 旋转方式 首先要区分每次旋转是绕固定轴旋转的 还是绕旋转之后的轴旋转的 绕固定轴旋转就是旋转过程中XYZ轴不变 绕旋
  • android自定义可缩放,移动图像裁剪框

    在实际项目中 经常要制作一个简易的图像裁剪功能 即获取一张图片 并用一个遮罩层选择目标范围并截取保存的功能 如下图所示 在此分享下该自定义视图的制作过程 需求说明 整一个视图包含一个透明的遮罩层 一个透明带白色边框的矩形 要实现的功能是 点
  • 代理IP与网络安全:保障跨境电商和游戏的顺畅运行

    在今天的数字时代 跨境电商和在线游戏已经成为全球互联网经济的两个重要组成部分 然而 这两者都需要强大的网络基础设施来支持其运行 同时 网络安全问题也变得愈发突出 在这个背景下 代理IP技术以及特别是Socks5代理协议 成为了网络工程师们重
  • react-router 5 管理路由

    实现功能 全局路由统一管理 支持配置路由重定向 路由懒加载 自定义meta字段等 全局路由拦截 支持读取路由meta配置 支持拦截跳转其他路由等 依赖版本 react 17 0 2 react router dom 5 3 0 react