React-router 路由学习

143 阅读2分钟
  1. React 路由菜单学习 渲染

  2. 学习来源:juejin.cn/post/684490…

  3. 感谢 @秋天不落叶 博主 提供的开源模版

  4. 针对项目中 使用的部分方法构建react-router;

一、初级router-配置 单router配置版本

主要学习 动态路由配置部分 以及 路由拦截器的使用方式

main.tsximport React from "react"
import { createRoot } from "react-dom/client"
import App from "./App"
import { BrowserRouter } from "react-router-dom"
const root = document.getElementById("root")
if (root) {
  createRoot(root).render(
    <React.StrictMode>
      <BrowserRouter>  // 这里还有个HashRouter 区别是#  BrowserRouter不带# 
        <App />
      </BrowserRouter>
    </React.StrictMode>
  )
}
App.jsximport * as React from "react"
import { Routes, Route } from "react-router-dom"
import Layout from "./Layout/index"
import Dashboard from "./views/dashboard/index"
import Login from "./views/login/index"
import NoMatch from "./views/noMatch/index"
export default function App() {
  return (
    <div>
      {/* 要注册的路由必须有Routes 包裹 */}
      <Routes>  
        <Route path="/" element={<Layout />}>
          <Route index element={<Dashboard />} />
          {/* 
              index :表示当前匹配的路由 
              path:路由路径
              element:展示的组件
          */}
          <Route path="login" element={<Login />} />
          <Route path="*" element={<NoMatch />} />
        </Route>
      </Routes>
    </div>
  )
}

二、hook 按模块封装 使用

import * as React from "react"

import Router from "./routes/index"
export default function App() {
  return (
    <div>
          {/* 路由拦截器  包裹在Router组件前 */}
      <AuthRouter>
        <Router />
      </AuthRouter>
      {/* Loaing */}
    </div>
  )
}

src/routes/index.tsx 中

import React from "react"
import { Navigate } from "react-router-dom"
import { useRoutes } from "react-router-dom"

/* 路由页面 */
import Login from "@/views/login/index"
import Page404 from "@/views/errMessage/404"
import Page500 from "@/views/errMessage/500"

/* 子路由组 */
import Home from "./modules/home"
import Test from "./modules/test"
import Test2 from "./modules/test2"

export const RouteModule = [Home, Test, Test2]

/**
 * 路由配置项
 *
 * path:'路径'            // 路径,如果不是多级嵌套,可为 ' '
 * hidden:true           // 设置为true时不会出现在侧边栏
 * name:'router-name'     // 设定路由名,此项必填 (也是唯一标志名)
 * element:<login />     // 组件
 * alwaysShow: true       // 设置该属性为true后,侧边栏就会出现多级嵌套,否则不会出现
 * meta:{
 *   title:'title'        // 设置该路由在侧边栏和面包屑的name
 *   icon:'svg-name'      // 设置该路由的图标,对应路径 src/icons/svg
 * }
 */

export const rootRouter = [
  {
    path: "/login",
    element: <Login />,
    meta: {
      title: "登录页",
    },
  },
  {
    path: "/",
    element: <Navigate to="/home" />,
  },
  ...RouteModule,
  {
    path: "/404",
    element: <Page404 />,
    meta: {
      title: "404页面",
    },
  },
  {
    path: "/500",
    element: <Page500 />,
    meta: {
      title: "500页面",
    },
  },
  {
    path: "*",
    element: <Navigate to="/404" />,
  },
]

const Router = () => {
  const routes = useRoutes(rootRouter)
  return routes
}

export default Router

三、react中加入拦截器

加入拦截器
import React from 'react'
import { useLocation, Navigate } from 'react-router-dom'
import rootRouter from '@/routes'
import { getUserAPI } from '@/api/modules/user'
// mobx
import useStore from '@/store'

/**
 * @description 递归查询对应的路由
 * @param {String} path 当前访问地址
 * @param {Array} routes 路由列表
 * @returns array
 */

// // 设置白名单
const whitePaths = ['/login', '/404', '/500']
// 路由守卫配置函数
export const AuthRouter = (props: any) => {
  const { pathname } = useLocation()
  let {
    useUserStore: { token, setUserInfo, userInfo },
  } = useStore()

  // 第一步 判断有无 token
  if (token) {
    // 第二步 判断是否前往login页面,等于跳转 '/', 不等于则继续判断
    if (pathname === '/login') {
      return <Navigate to="/" replace />
    } else {
      // 第三步 判断是否拿到用户个人信息及权限,没拿到则进行axios请求数据,进行信息存储及权限路由渲染,否则直接放行
      if (Object.keys(userInfo).length < 1) {
        // 获取用户个人信息 (此处使用 async await会报错)
        getUserAPI()
          .then((res) => {
            setUserInfo(res.data as any)
          })
          .catch((err) => {})

        // 合并路由
        return props.children
      } else {
        return props.children
      }
    }
  } else {
    if (whitePaths.includes(pathname)) {
      return props.children
    } else {
      return <Navigate to="/login" replace />
    }
  }
}