• react_14


    动态路由

    路由分成两部分:

    • 静态路由,固定的部分,如主页、404、login 这几个页面

    • 动态路由,变化的部分,经常是主页内的嵌套路由,比如 Student、Teacher 这些

    动态路由应该是根据用户登录后,根据角色的不同,从后端服务获取,因为这些数据是变化的,所以用 mobx 来管理

    在src\store\路径下新建RoutesStore.tsx

    1. import axios from "axios";
    2. import {
    3. LoginReq,
    4. LoginResp,
    5. Menu,
    6. MenuAndRoute,
    7. Route,
    8. } from "../model/Student";
    9. import R from "../model/R";
    10. import { makeAutoObservable, runInAction } from "mobx";
    11. import { Link, Navigate, RouteObject } from "react-router-dom";
    12. import { load } from "../router/MyRouter";
    13. import A8Main from "../pages/A8Main";
    14. import A8NotFound from "../pages/A8NotFound";
    15. import { ItemType } from "antd/es/menu/hooks/useItems";
    16. import Icon from "./Icon";
    17. //其中 convertMenu 为核心方法,负责将服务器返回的 Menu 转换成 antd Menu 组件需要的 Menu
    18. function convertMenu(m: Menu): ItemType {
    19. const Label = m.routePath ? <Link to={m.routePath}>{m.label}Link> : m.label;
    20. return {
    21. key: m.key,
    22. label: Label,
    23. icon: <Icon name={m.icon}>Icon>,
    24. children: m.children && m.children.map(convertMenu),
    25. };
    26. }
    27. class RoutesStore {
    28. dynamicRoutes: Route[] = [];
    29. dynamicMenus: Menu[] = [];
    30. token: string = "";
    31. message: string = "";
    32. state: string = "pending";
    33. async login(loginReq: LoginReq) {
    34. this.state = "pending";
    35. const resp1 = await axios.postLoginResp>>(
    36. "http://localhost:8080/api/loginJwt",
    37. loginReq
    38. );
    39. if (resp1.data.code === 999) {
    40. const resp2 = await axios.getMenuAndRoute>>(
    41. `http://localhost:8080/api/menu/${loginReq.username}`
    42. );
    43. runInAction(() => {
    44. this.dynamicRoutes = resp2.data.data.routeList;
    45. localStorage.setItem(
    46. "dynamicRoutes",
    47. JSON.stringify(this.dynamicRoutes)
    48. );
    49. this.dynamicMenus = resp2.data.data.menuTree;
    50. localStorage.setItem("dynamicMenus", JSON.stringify(this.dynamicMenus));
    51. this.token = resp1.data.data.token;
    52. localStorage.setItem("token", this.token);
    53. this.state = "success";
    54. });
    55. } else {
    56. runInAction(() => {
    57. this.state = "error";
    58. this.message = resp1.data.message || "未知错误";
    59. });
    60. }
    61. }
    62. /* async fetch(username: string) {
    63. const resp = await axios.get>(
    64. `http://localhost:8080/api/menu/${username}`
    65. );
    66. runInAction(() => {
    67. this.dynamicRoutes = resp.data.data.routeList;
    68. //当在浏览器地址栏重新输入路径的时候,会重新向7070服务器发送一个请求,导致RoutesStore.tsx重新执行,
    69. //导致路由对象重新被创建,那么登录之后获得的动态路由数据就会丢失,所以为了防止这种情况,把登录后获得的
    70. //路由数据存入到localStorage中
    71. localStorage.setItem("dynamicRoutes", JSON.stringify(this.dynamicRoutes));
    72. this.dynamicMenus = resp.data.data.menuTree;
    73. localStorage.setItem("dynamicMenus", JSON.stringify(this.dynamicMenus));
    74. });
    75. } */
    76. get routes() {
    77. const staticRoutes: RouteObject[] = [
    78. {
    79. path: "/login",
    80. element: load("A8Login"),
    81. },
    82. {
    83. path: "/",
    84. element: <A8Main>A8Main>,
    85. children: [],
    86. },
    87. {
    88. path: "/404",
    89. element: <A8NotFound>A8NotFound>,
    90. },
    91. // 使用这个路径,上面的路径匹配不到时,显示notFound页面,但是路径还是输入的路径不变
    92. { path: "/*", element: <A8NotFound>A8NotFound> },
    93. // 使用这种路径写法的时候,上面的路径匹配不到时,页面是重定向到notFound,路径会跳转到404
    94. {
    95. path: "/*",
    96. element: <Navigate to={"/404"}>Navigate>,
    97. },
    98. ];
    99. staticRoutes[1].children = this.dynamicRoutes.map((r) => {
    100. return { path: r.path, element: load(r.element) };
    101. });
    102. return staticRoutes;
    103. }
    104. get menus() {
    105. return this.dynamicMenus.map(convertMenu);
    106. }
    107. get username() {
    108. if (this.token.length === 0) {
    109. return "";
    110. }
    111. //token 的前两部分都可以解码出来,其中 [1] 就是 token 的内容部分
    112. const json = atob(this.token.split(".")[1]);
    113. //parse方法把字符串还原成对象
    114. return JSON.parse(json).sub;
    115. }
    116. constructor() {
    117. makeAutoObservable(this);
    118. //页面刷新会重新调用构造器,这个时候从localStorage中获取存储的路由数据
    119. const routesJson = localStorage.getItem("dynamicRoutes");
    120. this.dynamicRoutes = routesJson ? JSON.parse(routesJson) : [];
    121. const menusJson = localStorage.getItem("dynamicMenus");
    122. this.dynamicMenus = menusJson ? JSON.parse(menusJson) : [];
    123. }
    124. reset() {
    125. localStorage.removeItem("dynamicRoutes");
    126. this.dynamicRoutes = [];
    127. localStorage.removeItem("dynamicMenus");
    128. this.dynamicMenus = [];
    129. localStorage.removeItem("token");
    130. this.token = "";
    131. this.state = "pending";
    132. }
    133. }
    134. export default new RoutesStore();
    • 其中用 localStorage 进行了数据的持久化,避免刷新后丢失数据

    • 跳转若发生错误,可能是因为组件懒加载引起的,需要用 Suspense 解决

      1. root.render(
      2. <ConfigProvider locale={zhCN}>
      3. <BrowserRouter>
      4. <Suspense fallback={<h3>加载中...h3>}>
      5. <MyRouter>MyRouter>
      6. Suspense>
      7. BrowserRouter>
      8. ConfigProvider>
      9. )

  • 相关阅读:
    python采集小破站视频弹幕
    进程同步互斥之吸烟者问题,读者写者问题,哲学家进餐问题
    vscode 配置 Rust 运行环境
    企业网络安全保障团队建设构想
    OpenAI 封了中国 API 后,国外开发者却先转向了 Claude
    C语言系统化精讲(五):C语言格式化输入和运算符与表达式
    [NOIP2002 提高组] 字串变换
    2022,TO B投资不相信「故事」
    java计算机毕业设计VUE教育网站设计与实现源码+数据库+系统+lw文档
    优化 Redis 集群缓存分配:解决节点间分配不均导致内存溢出问题
  • 原文地址:https://blog.csdn.net/weixin_44478828/article/details/134212429