React 像 vue 一样配置页面路由,并支持重定向路由,路由守卫等(使用 useRoutes 完成)

  • 希望达到跟 vue 一样,在 js 配置中则完成路由重定向的等基础操作,不太习惯使用 Routes、Route 等互相包裹的方式。

  • 所有基于 react-router-dom@6.15.0 封装了一个路由组件,并附带展示个路由守卫组件。

  • 路由组件 - ExRouter.tsx<ExRouter routes={routes}></ExRouter>

    扩展路由配置,支持重定向,以及方便扩展其他属性。

    js 复制代码
    // 基于 react-router-dom@6.15.0 封装
    import { useRoutes, Navigate, IndexRouteObject, NonIndexRouteObject } from 'react-router-dom'
    import { useLocation } from 'react-router'
    
    /**
     * @description: 扩展 IndexRouteObject
     */
    interface exIndexRouteObject extends IndexRouteObject {
      /**
       * @description: 重定向路由地址
       */
      redirect?: string
    }
    
    /**
     * @description: 扩展 NonIndexRouteObject
     */
    interface exNonIndexRouteObject extends NonIndexRouteObject {
      /**
       * @description: 重定向路由地址
       */
      redirect?: string
    }
    
    /**
     * @description: 路由对象类型
     */
    export type exRouteObject = exIndexRouteObject | exNonIndexRouteObject;
    
    /**
     * @description: 组件参数
     */
    type props = {
      /**
       * @description: 路由列表
       */
      routes: exRouteObject[],
      /**
       * @description: 子组件列表
       */
      children?: any
    }
    
    const Component = (props: props) => {
      // 当前导航对象
      const location = useLocation()
      // 找到路由对象
      const findRoute = (routes: exRouteObject[], location:any): any => {
        // 当前层级检查一轮
        let route: any = routes.find((item: any) => item.path === location.pathname)
        // 没有则搜索当前层级同级子页面
        if (!route) {
          // 排查,找到停止
          routes.some((item: any) => {
            // 取出子列表
            const children: exRouteObject[] = item?.children || []
            // 进行排查
            route = findRoute(children, location) 
            // 有值则暂停
            return !!route
          })
        }
        // 返回
        return route
      }
      // 找到当前路由
      const route: any = findRoute(props.routes, location)
      // 返回渲染
      return (
        <>
          {/* 加载所有路由 */}
          { useRoutes(props.routes) }
          {/* 检查当前路由是否需要重定向 */}
          { route?.redirect && <Navigate to={route.redirect} replace /> }
        </>
      )
    }
    
    export default Component
  • 路由拦截(路由守卫)组件:<BeforeEach></BeforeEach>

    js 复制代码
    // import { Navigate, useLocation, useSearchParams } from 'react-router-dom'
    
    const Component = (props: any) => {
      // // 接收路由参数
      // const [searchParams] = useSearchParams()
      // // 当前导航对象
      // const location = useLocation()
      // // token (检查本地或路由参数)
      // const token = 'xxxx'
      // // console.log(location, searchParams.get('token'))
      // // 路由权限校验
      // if (location.pathname.includes('/login') && token) {
      //   // 跳转登录页 && token有值
      //   return <Navigate to="/home" replace />
      // } else if (!location.pathname.includes('/login') && !token) {
      //   // 不是跳转登录页 && token无值
      //   return <Navigate to="/login" replace />
      // }
      // 验证通过
      return props.children
    }
    
    export default Component
  • 上面两个组件在路由中的使用:

    js 复制代码
    import React from 'react'
    import { Navigate } from 'react-router-dom'
    import BeforeEach from './BeforeEach'
    import ExRouter from './ExRouter'
    
    // 懒加载
    const lazyload = (path: string) => {
      // 加载组件
      let Component=React.lazy(()=>{return import (`@/${path}`)})
      // 返回渲染
      return (
        <React.Suspense fallback={<>请等待·····</>}>
          <Component />
        </React.Suspense>
      )
    }
    
    // 基础路由
    const baseRoutes: Record<string, any>[] = [
      {
        path: '/home',
        element: lazyload('views/home'),
      },
      {
        path: '/user',
        element: lazyload('views/user'),
      },
      {
        path: '/layout',
        redirect: '/layout/home',
        element: lazyload('layouts/BaseLayout'),
        children: [
          {
            path: '/layout/home',
            redirect: '/layout/home/home1',
            element: lazyload('views/home'),
            children: [
              {
                path: '/layout/home/home1',
                element: lazyload('views/home')
              }
            ]
          }
        ]
      }
    ]
    
    // 路由列表
    const routes: Record<string, any>[] = [
      ...baseRoutes,
      {
        path: "/404",
        element: (<>页面地址不存在</>),
      },
      { path: "/", element: <Navigate to="/home" /> },
      { path: "*", element: <Navigate to="/404" /> },
    ]
    
    // 加载配置式路由
    function Router () {
      return (
        <BeforeEach>
          {/* 加载所有路由 */}
          {/* { useRoutes(props.routes) } */}
          {/* 加载所有路由,并扩展路由配置 */}
          <ExRouter routes={routes}></ExRouter>
        </BeforeEach>
      )
    }
    
    // 导出
    export default Router
相关推荐
给钱,谢谢!5 小时前
React + PixiJS 实现果园成长页:从状态机到浇水动画
前端·react.js·前端框架
漓漾li12 小时前
每日面试题(2026-05-20)- 前端
前端·react.js
&&月弥13 小时前
react快速入门
前端·react.js
用户8876654266314 小时前
Zustand 项目落地:从全局状态、Store 拆分到真实业务封装
react.js·前端框架
ArkPppp14 小时前
卡顿减少50%:公司内部前端项目的一次性能排查实录(含火焰图截图)
前端·react.js
Highcharts.js14 小时前
数学函数双曲线音频图表(y=1/x 双曲线)|图表代码示例
前端·react.js·实时音视频·highcharts·音频图表·双曲线图表
放下华子我只抽RuiKe515 小时前
React 从入门到生产(一):JSX 与组件思维
前端·javascript·人工智能·pytorch·深度学习·react.js·前端框架
用户8876654266317 小时前
Redux Toolkit 项目落地:从 slice、thunk 到可维护的前端状态管理
react.js
Maimai1080817 小时前
前端如何落地 SSE:从实时评论到可复用的实时数据 Hook
前端·javascript·react.js·前端框架·web3·状态模式·webassembly
暗冰ཏོ18 小时前
React超详细学习指南
前端·react.js·前端框架