普通视图

发现新文章,点击刷新页面。
昨天以前首页

面向企业级应用的React路由管理体系:react-router-mannge实践

作者 Shinpei
2025年4月13日 17:40

当今复杂的企业级前端应用开发中,尤其是中后台应用中,路由管理已不再是简单的页面切换,而是演变为一套完整的状态管理、权限控制、导航构建和用户体验优化的综合解决方案。react-router-manage 应运而生,它在 react-router v6 的基础上构建了一个更高维度的路由管理生态,为开发者提供了一种优雅而高效的前端架构范式。

该库在网易云商多个项目中已稳定运行4年之久,在2年前也把它开源出来,但没有做过推广。但是两年过去了,react-router社区还是没有一套完整的解决方案,反而在react-router v7中自己演变成了一个和remix高度融合的一个框架项目,不由的想,这已经不是我想要的路由,于是,我想和和大家一起共建react-router生态型路由

GitHub地址

突破传统路由管理的局限

传统的React应用路由管理面临多重挑战:分散式的路由配置导致维护困难;权限与路由耦合度高;动态路由管理复杂;缺乏统一的路由守卫机制。这些问题在大型应用中尤为突出,严重影响了开发效率和代码质量,相信大家用了我这个库,开发效率一定能有很大的提升。详细的使用文档可参考 reac-router-manage使用文档或者 GitHub

react-router-manage 通过一种集中式声明式的配置方式,彻底颠覆了传统路由管理的思维模式,先来看如下示例 codesandbox

import React from "react";
import { MRouter, defineRouterConfig, useRouter } from "react-router-manage";
import "./styles.css";

const Users = () => {
  const { currentRoute } = useRouter();
  return <div>Users - {currentRoute.title}</div>;
};
const Profile = () => {
  const { currentRoute } = useRouter();
  return <div>Profile - {currentRoute.title}</div>;
};

const routerConfig = defineRouterConfig({
  basename: "/",
  // 配置层级导航
  routes: [
    {
      path: "/",
      redirect: "/user",
      name: "根节点",
      items: [
        {
          name: "user", // 每个路由对应一个全局唯一的name
          path: "user", // 路径会自动在内部转换为 /user, 由于这里没有配置component,进入 /user 会重定向到 /user/list
          title: "用户中心", // 路由名字
          items: [
            // items用于配置具有层级结构的导航,例如面包屑导航,
            {
              name: "userList",
              path: "list", // 路径会自动在内部转换为 /user/list
              component: Users,
              title: "用户列表",
            },
            {
              name: "profile",
              path: "profile", // 路径会自动在内部转换为 /user/list
              component: Profile,
              title: "个人中心",
            },
          ],
        },
      ],
    },
  ],
});

function App() {
  return (
    <MRouter routerConfig={routerConfig}>
      {(children) => <Layout>{children}</Layout>}
    </MRouter>
  );
}

function Layout({ children }) {
  const { routesMap, navigate } = useRouter();
  const navRoute = routesMap.user;
  return (
    <div>
      <div className="nav">
        导航
        <span>
          {navRoute.items.map((route) => {
            return (
              <button
                onClick={() => navigate(route.path)}
                style={{ marginLeft: 20 }}
              >
                去{route.title}
              </button>
            );
          })}
        </span>
      </div>
      <div className="content">{children}</div>
    </div>
  );
}

export default App;


安装

npm install react-router-manage

核心优势:超越简单的路由切换

1. 声明式配置与中央管理

告别以往零散和嵌套的路由定义方式,react-router-manage 采用集中声明式配置,通过单一数据源的方式实现路由的全局管理,大幅提升了路由系统的可维护性和可扩展性。

自动解析获取当前路由参数

import React from "react";
import { useRouter } from "react-router-manage";

cconst User = () => {
  // 若url为 /user/profile?id=9527
  const {query, params} = useRouter();
  
  // 这里query.id为9527
  return <div><{query.id}</div>;
};

export default UserList

2.便捷式的路由导航

路由跳转不再需要知道具体pathname

import React from "react";
import { useRouter } from "react-router-manage";

cconst UserList = () => {
  const {routesMap, naviagete} = useRouter();
  const onClick = () => {
      // 所有路由的配置都会放到routesMap对象里
      navigate(routesMap.profile.pathname)
  }
  return <div><button>跳转我的个人中心</button></div>;
};

export default UserList

快捷拿到子级路由

例如我要渲染 /user下的自己路由菜单,点击跳转到对应的路由

import React from "react";
import { useRouter } from "react-router-manage";

cconst UserCenter = () => {
  const {routesMap, navigate} = useRouter();
  
  // 拿到 /user下的 /user/profile 和/user/list
  
  const items = routesMap.user.items;
  
  return <div>{
        items.map(item => {
            return <button onClick={() => navigate(item.pathname)}>跳转到{item.name}</button>
        })
    }</div>;
};

export default UserCenter

便携式参数传递

navigate对象支持传路由参数query, params,navigate: (to: string, {query: Record<string, any>; params: Record<string, any>; state: any}) => void},如下示例

import React from "react";
import { useRouter } from "react-router-manage";

cconst UserList = () => {
  const {routesMap, naviagete} = useRouter();
  const onClick = () => {
      // 所有路由的配置都会放到routesMap对象里
      navigate(routesMap.profile.pathname, {
         query: {id: 9527} // 会自动拼成 /user/profile?id=9527
      })
  }
  return <div><button>跳转用户A的个人中心</button></div>;
};

export default UserList

3. 动态路由操作的优雅解决方案

在复杂应用的微前端架构或权限变化场景中,动态调整路由结构是一项常见需求。react-router-manage 提供了三个强大的 hooks, useAddRoutes,useUpdateRoutes, useRemoveRoutes。你可以很简单的动态操作路由

// 添加路由
const addRoutes = useAddRoutes();
// 动态更新路由配置
const updateRoutes = useUpdateRoutes();
// 移除路由
const removeRoutes = useRemoveRoutes();

添加路由 useAddRoutes

import React from 'react';
import {useRouter, useAddRoutes} from 'react-router-manage';
const UsersManage = () => {
  const {currentRoute} = useRouter();
  return <div>UsersManage - {currentRoute.title}</div>;
}
const AddRoutesWrapComponent = ({ children }) => {
  const addRoutes = useAddRoutes();
  const onAdd = () => {
      addRoutes([
          {
            parentName: "user", // 父路由名称 name
            title: "员工管理页",
            name: "userManage",
            path: "manage",
            component: UsersManage,
          }
    ]);
  }

  return <button onClick={onAdd}>添加一个路由</button>;
};

在上述代码中,点击button即可在 /user路径下,增加一个/user/manage的路由

更新路由 useUpdateRoutes

import React from 'react';
import {useRouter, useAddRoutes, useUpdateRoutes} from 'react-router-manage';
const UsersManage = () => {
  const {currentRoute} = useRouter();
  return <div>UsersManage - {currentRoute.title}</div>;
}
const AddRoutesWrapComponent = ({ children }) => {
  const addRoutes = useAddRoutes();
  const onAdd = () => {
      addRoutes([
          {
            parentName: "user", // 父路由名称 name
            title: "员工管理页",
            name: "userManage",
            path: "manage",
            component: UsersManage,
          }
    ]);
  }
  
  const onUpdate = () => {
    updateRoutes([
      {
        routeName: "userManage",
        routeData: {
          title: "我被修改了"
        }
      }
    ]);
  }

  return (<div>
      <button onClick={onAdd}>添加一个路由</button>
      <button onClick={onUpdate}>更新当前路由</button>
  </div>);
};

此时点击按钮会发现,

4. 多层次的权限控制体系

react-router-manage 突破了传统路由权限的局限性,提供了从全局到局部的多级权限控制机制:

  • 声明式权限配置:通过 code 属性简洁地定义路由访问权限
  • 权限继承模式:支持 parent 和 children 两种权限继承模式
  • 动态权限校验:结合 beforeEachMount 和 beforeEnter 实现精细的动态权限控制

5. 全面的路由守卫系统

借鉴了Vue Router 的优秀设计,react-router-manage 引入了完整的路由守卫机制:

  • 全局前置守卫:beforeEachMount
  • 路由级前置守卫:beforeEnter
  • 组件级离开守卫:useBeforeLeave

这种分层的守卫架构使得开发者可以精确控制路由导航的每个环节,优雅处理权限验证、数据预加载和离开确认等复杂场景。

6.智能导航生成引擎

可自动生成符合企业规范的面包屑导航、菜单导航

从 React Router v5 到 v6 的平滑迁移

React Router v6 带来了诸多改进,但也带来了升级成本。react-router-manage 通过提供兼容层,大幅降低了迁移门槛:

  • 保留部分 v5 风格的 API
  • 透明处理 v6 的新特性
  • 引入 useHistory 等过渡性 hook

企业级应用的首选路由解决方案

React Router Manage 已在网易云商等多个企业级应用中经受了实战检验,证明了其在大型复杂应用中的可靠性和扩展性。它特别适合以下场景:

  • 大型管理后台:复杂权限系统、多层级导航
  • 微前端架构:动态路由管理、模块隔离
  • 多团队协作:标准化的路由配置、一致的导航体验

react-router-manage企业级路由方案使用文档

作者 Shinpei
2025年4月13日 16:41

react-router-manage

功能简介

react-router-manage基于react-router v6版本实现,通过配置可实现路由的鉴权、路由守卫、路由的增删改查等功能。由于react-router v5升级到v6有较大的成本,react-router-manage提供了原来 v5 部分的 api 用于兼容使用 v5 的项目,用于平滑升级 v6

  • 🛠 [config router] - 集中配置路由,快捷、方便管理。
  • + [addRoutes] - 动态增加路由:可使用 hookuseAddRoutes添加路由,自动刷新视图。
  • ➖ [removeRoutes] - 动态删除路由:可使用 hookuseRemoveRoutes删除路由,自动刷新视图。
  • 🖇 [updateRoutes] - 动态修改路由:可使用 hookuseUpdateRoutes修改路由。
  • 🔐 [permission] - 权限控制:配置路由的 code,自动管理路由的权限
  • 👨‍✈️‍ [Route guard] - 提供路由进入时的回调 beforeEnter and beforeEachMount, 路由离开时的钩子 useBeforeLeave
  • 🌲 [navigation] - 层级导航:支持层级导航,自动实现父子级路由的导航栏生成,例如面包屑、菜单导航

安装


npm install react-router-manage --save

示例

配置项

routerConfig

路由的全局配置

字段名 说明 类型 是否必填
basename 路由的路由前缀 string 非必填,默认 /
routes 路由的层级配置 RouteTypeI[] 必填
beforeEachMount 每个路由在渲染前调用 (to: RouteTypeI | undefined, next: ({path?: string; name: string} | React.ComponentType<any>) => void): void 非必填
autoDocumentTitle 文档的 title 会根据路由切换而改变 boolean | (RouteTypeI[]) => string 非必填, 默认 false
LoadingComponent 用于 Suspense 加载异步组件时配置 fallback 或在有 beforeEnter 钩子的next时,显示加载中 React.FunctionComponent not required
路由模式

路由模式目前有两种

  • history模式
  • hash模式

一个简单的全局配置(history模式

import React from 'react';
import { MRouter, defineRouterConfig } from 'react-router-manage';

const routerConfig = defineRouterConfig({
  basename: '/',
  routes: [{...}], // 请查看下方路由配置 routes
  // autoDocumentTitle: true, // 设置true,会自动设置变换document.title,
  // autoDocumentTitle: (routes) => return `网易云商-${routes.map((i) => i.title).join('-')}`, // 自定已配置document.title的设置

  // beforeEachMount: (to, next) => { // 配置全局的路由进入守卫,可查看下方全局路由守卫介绍
  //   console.log(to)
  //   next();
  // }
})

function App () {
  return (
    <MRouter routeConfig={routeConfig}>
      {(children) => children}
    </MRouter>
  )
}

一个简单的全局配置(hash模式

import React from 'react';
import { MHRouter, defineRouterConfig } from 'react-router-manage';

const routerConfig = defineRouterConfig({
  basename: '/',
  routes: [{...}], // 请查看下方路由配置 routes
  // autoDocumentTitle: true, // 设置true,会自动设置变换document.title,
  // autoDocumentTitle: (routes) => return `网易云商-${routes.map((i) => i.title).join('-')}`, // 自定已配置document.title的设置

  // beforeEachMount: (to, next) => { // 配置全局的路由进入守卫,可查看下方全局路由守卫介绍
  //   console.log(to)
  //   next();
  // }
})

function App () {
  return (
    <MHRouter routeConfig={routeConfig}>
      {(children) => children}
    </MHRouter>
  )
}

路由配置 routes

字段名 说明 类型 是否必填
name 路由的名称, 名称全局唯一、不能重复,用于获取路由 string 必填
path 路由的路径,组合后的完整路径全局唯一、不能重复,但是如果是嵌套的子路由,可以不配置, 相当于Route组件中设置index属性 string 必填
title 路由的中文名称,显示的名称,用于自动生成导航和面包屑中 string 非必填
index 同级有多个路由,会找带 index 的路由作为进入的路由 boolean 非必填
component 路由匹配的组件, 如果没有配置,则会跳到下一级有权限的路由 React.Component | React.FunctionComponent 非必填
items 视觉上的子级路由,用于导航时的父子级关系,实际为同一级路由 RouteTypeI[] 非必填
children 子级路由、在 v6 版本中渲染在 Outlet组件中 RouteTypeI[] 非必填
props 渲染组建时候会自动注入 Props 里面的内容, <Component {...props}/> Record<string, any> 非必填
hidden 导航的显示与隐藏 boolean 非必填, 默认 false
code 用于权限校验,会对比permissionList里的值 string| string[]| (route: RouteTypeI) => boolean 非必填,默认无
redirect 路由重定向到指定路由,优先级高于 component string 非必填,默认无
beforeEnter 渲染该路由钱调用的方法,如果调用next中传入了组件,则会渲染该组件,路由配置的组件则不会渲染 (to: RouteTypeI | undefined, next: (options?: {name?: string; path?: string} | React.ComponentType<any>) => void): void 非必填, 默认无
beforeLeave 离开路由前调用的回调,需主动调用next (to: RouteTypeI | undefined,from: RouteTypeI | undefined, next: () => void): void 非必填
meta 一些自定义的信息可以放这里,currentRoute.meta可以获取到该字段 Record<string, any> 非必填
fullscreen 是否全屏,在base-layout-router中监测到当前route fullscreentrue,则会隐藏导航栏 boolean 非必填,默认无
icon 用于显示导航的 icon string 非必填, 默认无
type 如果typenull字符串,则此路由不会真正渲染,但是可以设置正确的 currentRoute real | null 非必填,默认 real
bredcrumbs 用于配置路由中面包屑的配置, antd-breadcrumbs BreadcrumbsI 非必填
BreadcrumbsI
字段名 说明 类型 是否必填
isRoot 是否是面包屑的根节点,如果是,则从下一级开始算 boolean false
text 面包屑的名称,如果不配置,则默认使用route.title string | React.ReactNode | (route: RouteTypeI) => React.ReactNode 非必填
hidden 是否隐藏本级面包屑显示 boolean false

注意事项

  • 如果在code里配置了一个函数,由于在路由初始化会批量调用,请不要进行异步调用,如果需要建议使用beforeEnter达到同样效果
  • 如果父级路由没有配置 component, 跳转到该路由则会寻找 items,children 下第一个有权限的路由,若找不到,则会显示无权限页面
  • 如果redirectcomponent同时进行了配置,则component会被忽略
  • beforeEnterbeforeEachMountnext可传入一个组件,若传入则会渲染该组件, 如果在 react 使用严格模式,则函数可能会调用两次,这个是正常情况
items 与 children

通过 ys-router,你可以使用children, items配置来表达路由导航的父子关系。

items 同一级别的路由,父级与子级渲染一个

/**
 *  文章列表页和文章详情页在不同的页面
 *  /user/article/list  文章列表页面
 *  /user/article/detail 文章详情页
 * */
/user/article/list                     /user/article/detail
+------------------+                  +-----------------+
| +--------------+ |                  | +-------------+ |
| | ------------ | |  +------------>  | | content     | |
| | ------------ | |                  | |             | |
| | ------------ | |                  | |             | |
| | ------------ | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

一个有基本路由配置的示例

import React from "react";
import { MRouter, defineRouterConfig } from "react-router-manage";

const Users = () => {
  return <div>Users</div>;
};
const Profile = () => {
  return <div>Profile</div>;
};

const appRouterConfig = defineRouterConfig({
  basename: "/",
  // 配置层级导航
  routes: [
    {
      name: "user", // 每个路由对应一个全局唯一的name
      path: "user", // 路径会自动在内部转换为 /user, 由于这里没有配置component,进入 /user 会重定向到 /user/list
      title: "用户中心", // 路由名字
      items: [
        // items用于配置具有层级结构的导航,例如面包屑导航,
        {
          name: "userList",
          path: "list", // 路径会自动在内部转换为 /user/list
          component: Users,
          title: "用户列表"
        },
        {
          name: "profile",
          path: "profile", // 路径会自动在内部转换为 /user/list
          component: Profile,
          title: "个人中心"
        }
      ]
    }
  ]
});

function App() {
  return <MRouter routeConfig={routeConfig}>{children => children}</MRouter>;
}
children 嵌套路由

一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如:

/**
 * 文章列表页和文章详情页在相同的页面
 *  /user/article/list  文章列表页面
 *  /user/article/detail 文章详情页
 * */
/user/article/list                     /user/article/detail
+------------------+                  +-----------------+
| user             |                  | user          |
| +--------------+ |                  | +-------------+ |
| |     list     | |  +------------>  | | content     | |
| | ------------ | |                  | |             | |
| | ------------ | |                  | |             | |
| | ------------ | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

一个有嵌套路由配置的示例

import React from "react";
import Outlet from "react-router";
import { MRouter, defineRouterConfig } from "react-router-manage";

const Users = () => {
  return (
    <div>
      <div>Users</div>
      <Outlet />
    </div>
  );
};
const Profile = () => {
  return <div>Profile</div>;
};

const UserProfile = () => {
  return <div>UserProfile</div>;
};
const UserArticles = () => {
  return <div>UserArticles</div>;
};

const appRouterConfig = defineRouterConfig({
  basename: "/",
  // 配置层级导航
  routes: [
    {
      name: "user", // 每个路由对应一个全局唯一的name
      path: "user", // 路径会自动在内部转换为 /user, 由于这里没有配置component,进入 /user 会重定向到 /user/list
      title: "用户中心", // 路由名字
      items: [
        // items用于配置具有层级结构的导航,例如面包屑导航,
        {
          name: "userList",
          path: "list", // 路径会自动在内部转换为 /user/list
          component: Users,
          title: "用户列表",
          children: [
            {
              name: "userProfile",
              path: "profile",
              title: "用户信息",
              component: UserProfile
            },
            {
              name: "userArticle",
              path: "article",
              title: "用户文章列表",
              component: UserArticles
            }
          ]
        },
        {
          name: "profile",
          path: "profile", // 路径会自动在内部转换为 /user/list
          component: Profile,
          title: "个人中心"
        }
      ]
    }
  ]
});

function App() {
  return <MRouter routeConfig={routeConfig}>{children => children}</MRouter>;
}

权限路由

权限permissionMode支持两种模式 parent adn children, 默认是parent

  • 如果 permissionModeparent,如果父路由没有权限,那么子路由都没有权限
  • 如果 permissionModechildren,如果子路由有权限,那么父路由不管配置的有无权限,都会自动转为有权限

配置字符串 code 的批量校验

  • 需要在MRouter组件中传入permissionList,并设置 hasAuthtrue, 默认为 true
  • 需要在路由配置中配置 code,如果不配置,则默认有权限

一个鉴权配置的示例

const permissionList = [`admin`, "staff"]; // 代表当前用户是admin
// const permissionList = ['staff'] // 代表当前用户是员工

const appRouterConfig = defineRouterConfig({
  basename: "/",
  // 配置层级导航
  routes: [
    {
      name: "user", // 每个路由对应一个全局唯一的name
      path: "user", // 路径会自动在内部转换为 /user, 由于这里没有配置component,进入 /user 会重定向到 /user/list
      title: "用户中心", // 路由名字
      code: [`admin`, "staff"],
      items: [
        // items用于配置具有层级结构的导航,例如面包屑导航,
        {
          name: "userList",
          path: "list", // 路径会自动在内部转换为 /user/list
          component: Users,
          title: "用户列表",
          code: "admin" // 此路由如果是是员工,则会被过滤
          // code: (currentRoute) => {
          //   // 也可以在这里进行自定义的校验,
          //   // 不要在这里进行校验,因为这里是再初始化时进行批量的校验,如果要实现进入该路由才校验,请使用 beforeEachMount
          //   return getHasAuth(currentRoute);
          // }
        },
        {
          name: "profile",
          path: "profile", // 路径会自动在内部转换为 /user/list
          component: Profile,
          title: "个人中心",
          code: [`admin`, "staff"] // 都有个人中心
        }
      ]
    }
  ]
});

// hasAuth 可以不配置,默认为true
function App() {
  return (
    <MRouter routeConfig={routeConfig} permissionList={permissionList} hasAuth={true} permissionMode="parent">
      {children => children}
    </MRouter>
  );
}

beforeEachMount 的路由鉴权

修改上述的 appRouterConfig

const NoAuth = () => {
  return <div>无权限</div>;
};
const appRouterConfig = defineRouterConfig({
  basename: "/",
  // 配置层级导航
  routes: [
    {
      name: "user", // 每个路由对应一个全局唯一的name
      path: "user", // 路径会自动在内部转换为 /user, 由于这里没有配置component,进入 /user 会重定向到 /user/list
      title: "用户中心", // 路由名字
      items: [
        // items用于配置具有层级结构的导航,例如面包屑导航,
        {
          name: "userList",
          path: "list", // 路径会自动在内部转换为 /user/list
          component: Users,
          title: "用户列表"
        },
        {
          name: "profile",
          path: "profile", // 路径会自动在内部转换为 /user/list
          component: Profile,
          title: "个人中心"
        }
      ]
    }
  ],
  beforeEachMount: (to, next) => {
    if (to.name === "userList") {
      next();
    } else {
      next(NoAuth);
    }
  }
});

导出的 hooks

hooks 名 类型 用途
useAddRoutes () => (routes: RouteTypeI[]) => void 动态添加路由
useUpdateRoutes () => (routes: { routeName: string; routeData: Partial<RouteTypeI> }[]) => void 动态更新路由
useRemoveRoutes () => (routeNames: string[]) => void 动态删除路由
useBeforeLeave (fn: BeforeLeaveI, options: {beforeunload?: ((event?: Event) => any)}) => void 路由离开时的守卫,需调用 next 才可以正常跳转
useRouter () => RoutesStateStruct 路由存储的一些状态
useHistory () => BrowserHistory 获取historyreact-router v6 没有暴露,用户 v5 升级 v6 的平滑过度, 不推荐使用

路由导航 useRouter

useRouter可在组件中获取各类状态数据

useRouter() 返回的 state:RoutesStateStruct

字段名 说明 类型
currentRoute 当前路由对象 RouteTypeI
routesMap 所有的路由 name,path 对应的路由都存储在这个对象中 Record<string, RouteTypeI>
navigate 用于跳转路由 (to: string, {query: Record<string, any>; params: Record<string, any>; state: any}) => void}
authRoutes 认证后有权限的路由对象 RouteTypeI[]
routes 传入的路由对象 routes RouteTypeI[]
query 当前地址栏查询参数 Record<string, string>
params 当前地址栏动态路由查询参数 Record<string, string>
navigate

useRouter 返回的 navigate 是在 react-routeruseNavigate上进行的扩展,对路由的跳转做了一些拦截处理,所以大家不要使用react-router中的userNavigate

navigate 有两个参数,第一个参数为要跳转的路径,第二个参数为跳转的路由配置, 类型如下

(to: string, {query: Record<string, any>; params: Record<string, any>; state: any}) => void}

  • query, 在跳转路由的时候会自动把查询参数添加到地址中,例如 navigate('/user/detail', { query: {id: 13}}), 会在跳转的时候转为 /user/detail?id=13
  • params, 当配置了带有参数的动态路由,会自动替换, 例如 navigate('/user/detail/:id', { params: {id: 13}}), 会在跳转的时候转为 /user/detail/13
  • state, 这个是 history 原始的 state

currentRoute

currentRoute 包含配置的时候传入的路由信息,内部会自动添加 parent`` 用来标识父级路由, 例如: parentRoute = currentRoute.parent`

...
import { useRouter } from 'react-router-manage'
...

function Item() {
  const { currentRoute, routesMap } = useRouter();

  const onClick = () => {
    navigate(routesMap.LIST.path); // navigate接收一个字符串
  }
  return (
    <div><Button onClick={onClick}>跳转到LIST</Button></div>
  )
}

useBeforeLeave 组件中的路由守卫

useBeforeLeave 需要调用 next 才可以正常跳转

import { useBeforeLeave, useRouter } from 'react-router-manage';
import { Modal } from 'ppfish';

const function Item() {
  const {navigate, routesMap} = useRouter();
  useBeforeLeave((to, from, next) => {
    Modal.confirm({
      title: '您确定要跳转吗?',
      onOk: () => {
        next();
      }
    })
  })
  const onClick = () => {
    navigate(routesMap.List.path);
  }
  return (<div>
    <Button onClick={onClick}>跳转</Button>
  </div>)
}

动态路由

useAddRoutes

useAddRoutes 添加路由

const AddRoutesWrapComponent = ({ children }) => {
  const addRoutes = useAddRoutes();

  useEffect(() => {
    addRoutes([
      {
        parentName: "PAGE1", // 需传入parentName,不传则会插入到第一层级下
        title: "动态添加的页面",
        name: "add",
        path: "add",
        component: Page,
        code: "staff"
      }
    ]);
  }, []);
  return <div data-testid="__router-children">{children}</div>;
};
useUpdateRoutes

useUpdateRoutes 更新路由

const UpdateRoutesWrapComponent = ({ children }) => {
  const updateRoutes = useUpdateRoutes();

  useEffect(() => {
    updateRoutes([
      {
        routeName: "PAGE1",
        routeData: {
          title: "修改后的页面" // 修改title
        }
      }
    ]);
  }, [updateRoutes]);
  return <div data-testid="__router-children">{children}</div>;
};
useRemoveRoutes

useRemoveRoutes 删除路由

const RemoveRoutesWrapComponent = ({ children }) => {
  const removeRoutes = useRemoveRoutes();

  useEffect(() => {
    removeRoutes(["PAGE1"]); // 传入要删除的 route的name字段
  }, []);
  return <div data-testid="__router-children">{children}</div>;
};

路由守卫

全局路由守卫

| 名称 | 说明 | 类型 | | ----------------- | ---------------------------------------------------- | ------------------------------------------------------------------- | -------------------------------- | | beforeEachMount | 在每一个路由渲染之前调用, next必须调用才会渲染组件 | (to: RouteTypeI \| undefined, next: {name?: string; path?: string} | React.ComponentType<any>) =void |


import NoAuth from './NoAuth', // 无权限组件

const appRouterConfig = {
    basename: '/',
    routes: [
        {
            name: 'root',
            title: '根路径',
            path: '/',
            items: [
                {
                    name: 'page1',
                    title: '页面1',
                    path: 'page1',
                    components: Page,
                    custom: 'aaa',
                },
                {
                    name: 'page2',
                    title: '页面2',
                    path: 'page2',
                    components: Page2,
                    custom: 'bbb',
                }
            ]
        }
    ],
    beforeEachMount(to, next) {
        if (to.custom === 'aaa) {
            next(); // 调用,则会正常渲染该路由对应的组件
        } else {
            next(NoAuth) // 则渲染无权限组件
        }
    }
}

局部路由守卫

名称 说明 类型
beforeEnter 在当前路由渲染之前调用(在beforeEachMount之后), next 必须调用才会渲染组件 (to: RouteTypeI | undefined, next: {name?: string; path?: string} | React.ComponentType<any>): void
beforeLeave 离开路由前调用的回调, 需主动调用next才会正常跳转 (to: RouteTypeI | undefined,from: RouteTypeI | undefined, next: {name?: string; path?: string} | React.ComponentType<any>): void
import NoAuth from './NoAuth', // 无权限组件

const appRouterConfig = {
    basename: '/',
    routes: [
        {
            name: 'root',
            title: '根路径',
            path: '/',
            items: [
                {
                    name: 'page1',
                    title: '页面1',
                    path: 'page1',
                    components: Page,
                    custom: 'aaa',
                    beforeEnter: (to, next) => {
                        //...
                        next(); // 需要跳转则调用
                    },
                    beforeLeave: (to, next) => {
                        //...
                        next(); // 需要跳转则调用
                    }
                },
                {
                    name: 'page2',
                    title: '页面2',
                    path: 'page2',
                    components: Page2,
                     custom: 'bbb',
                }
            ]
        }
    ],
    beforeEachMount(to, next) {
        if (to.custom === 'aaa) {
            next(); // 调用,则会正常渲染该路由对应的组件
        } else {
            next(NoAuth) // 则渲染无权限组件
        }
    }
}

打算开发的内容

  • KeepAlive 的支持
  • 示例代码的完善
  • 路由切换过渡动画
❌
❌