前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React Router V6项目中的路由鉴权封装实践(Hooks)

React Router V6项目中的路由鉴权封装实践(Hooks)

原创
作者头像
用户10321458
发布2023-12-03 20:03:55
1.2K0
发布2023-12-03 20:03:55
举报

React Router V6项目中的路由鉴权封装实践(Hooks)

1. 前言

1.1 路由封装的好处

  • 路由鉴权集中管理: 封装路由组件允许你集中管理路由鉴权逻辑。这意味着在一个地方处理用户是否有权限访问某个路由,而不是在每个页面或组件中重复相同的鉴权逻辑。这有助于保持一致性,并简化了对路由鉴权的维护和更新。
  • 提高代码复用性: 封装路由组件可以促进代码的复用。你可以将通用的路由配置、鉴权逻辑或其他功能抽象为可复用的组件,以便在整个应用程序中多次使用。这降低了重复编写相似代码的需求,提高了代码复用性。
  • 易于扩展: 当项目需求变化时,封装的路由组件使得扩展和调整路由配置变得更加容易。你可以轻松地添加新的路由或更改现有路由的配置,而不会影响到整个应用程序的其他部分。
  • 更清晰的项目结构: 路由组件的再封装可以帮助建立清晰的项目结构。通过将路由相关的代码放在专用的文件或文件夹中,项目的结构更容易理解和导航,减少了代码文件的混杂性。

1.2 整体项目结构

代码语言:shell
复制
 - src
   - layout
       - index.ts  # UI主框架(鉴权之后才能进的)
   - tools
       - auth.ts   # 权限相关工具文件
   - router
       - router.tsx  # 路由组件注册
       - routerMap.tsx  # 路由表构建
       - privateRouter.ts  # 权限路由组件
       - router.ts  # 路由组件注册
   - pages #(下面都是随便弄的,要对自己的需求)
       - community.tsx  # 社区压面
       - login.tsx  # 登录界面
       - user.ts  # 用户界面
       - book.ts  # 书籍列表界面

2. 前期准备工作

2.1 安装依赖

代码语言:shell
复制
  pnpm add antd --save # 因为是一个小案例,所以做了基础的UI开发
  pnpm add react-router-dom --save #(现在默认是V6版本的路由)

2.2 编写工具文件

代码语言:typescript
复制
 /**
  * 设置token
  * @param token
  * @returns
  */
 export const setToken = (token: string) =>
     window.localStorage.setItem("auth_token", token);
 /**
  * 获取token
  * @returns
  */
 export const getToken = () => window.localStorage.getItem("auth_token");
 /**
  * 获取token
  * @returns
  */
 export const clearToken = () => window.localStorage.removeItem("auth_token");
 

2.3 编写具体页面组件

仅仅以社区列表这个组件为例,其实就是每个具体页面准备好

代码语言:typescript
复制
 import React from "react";
 
 export default function Community() {
     return <div>社区列表界面</div>;
 }
 

3. 路由组件的开发

3.1 配置项目路由的根组件

代码语言:typescript
复制
 import React from "react";
 import ReactDOM from "react-dom/client";
 import App from "./App.tsx";
 import { BrowserRouter } from "react-router-dom";
 
 ReactDOM.createRoot(document.getElementById("root")!).render(
     <React.StrictMode>
         <BrowserRouter>
             <App />
         </BrowserRouter>
     </React.StrictMode>
     //这里配置的是BrowserRouter,根据需要,可选择这个或者HashRouter,两者差别这里就略过了,可以看看router v6基础篇或其他文章
 );
 

3.2 守卫路由的编写

其实就是做了一个基本的鉴权与过期处理,自己项目如果有更多的需求,就在try里面加就可以了

代码语言:typescript
复制
 import { message } from "antd";
 import { ReactElement, useEffect } from "react";
 import { getToken } from "../tools/auth";
 import { useNavigate } from "react-router-dom";
 
 interface Props {
     children: ReactElement;
 }
 const PrivateRoute = ({ children }: Props) => {
     const navigator = useNavigate();
 
     // 对比时间戳是否超过48小时
     function isPast48Hours(timestamp: number): boolean {
         // 获取当前时间戳
         const currentTimestamp = Math.floor(Date.now() / 1000);
 
         // 计算时间差,单位为秒
         const timeDifference = currentTimestamp - timestamp;
 
         // 定义48小时的秒数
         const hours48InSeconds = 48 * 60 * 60;
 
         // 判断时间差是否超过48小时
         return timeDifference > hours48InSeconds;
     }
 
     useEffect(() => {
         try {
             const token: any = getToken();
             const tokenObj = JSON.parse(token);
             if (tokenObj === null || isPast48Hours(tokenObj.expired)) {
                 message.warning("token过期,请重新登录");
                 navigator(`/login`);
             }
         } catch (error) {
             message.warning("token过期,请重新登录");
             navigator(`/login`);
         }
     }, []);
     return <>{children}</>;
 };
 
 export default PrivateRoute;
 

3.3 路由映射表的编写

这里没有直接用<Route/>组件爱你包裹,而是先用js对象形式维护了一套路由表数据,方便其他诸如: 菜单/目录等组件的复用

代码语言:typescript
复制
 import { Navigate } from "react-router-dom";
 import Login from "../pages/login";
 import User from "../pages/User";
 import Community from "../pages/Community";
 import Book from "../pages/Book";
 import Layout from "../layout";
 import PrivateRoute from "./privateRoute";
 export const routerMap = [
     {
         path: "/login",
         element: <Login />,
     },
     {
         path: "/",
         element: (
             <PrivateRoute>
                 <Layout />
             </PrivateRoute>
         ),
         children: [
             {
                 path: "/user",
                 element: <User />,
             },
             {
                 path: "/community",
                 element: <Community />,
             },
             {
                 path: "/book",
                 element: <Book />,
             },
         ],
     },
     {
         path: "*",
         element: <Navigate to="/login" />,
     }, //其他没有被注册过的路径统一重定位到login
 ];
 

3.4 路由注册的编写

其实就是将原先的路由表数据注册为路由组件

代码语言:typescript
复制
 
 import { useRoutes } from "react-router-dom";
 import { routerMap } from "./routerMap";
 
 function Router() {
     const routerTab = useRoutes(routerMap); //注册前端路由表
 
     return <div>{routerTab}</div>;
 }
 
 export default Router;
 

3.5 路由渲染

代码语言:typescript
复制
 import Router from "./router/router";
 
 function App() {
     return (
         <>
             <Router />
         </>
     );
 }
 
 export default App;
 

4. 组件内应用

4.1 Layout组件应用测试

Layout布局组件,一个简单的小Demo来测试路由正确性,他会被权限组件<PrivateRoute/>包裹,受到保护

代码语言:typescript
复制
 import { Tabs, TabsProps } from "antd";
 import React from "react";
 import { Outlet, useNavigate } from "react-router-dom";
 import { clearToken } from "../tools/auth";
 export default function Layout() {
     const navigator = useNavigate();
     const items: TabsProps["items"] = [
         {
             key: "book",
             label: "书籍列表页面",
         },
         {
             key: "community",
             label: "社区列表页面",
         },
         {
             key: "user",
             label: "用户列表页面",
         },
         {
             key: "login",
             label: "退出登录",
         },
     ];
     const handleChangeRoute = (value: string) => {
         if (value === "login") {
             clearToken();
         }
         navigator(`/${value}`);
     };
     return (
         <>
             <div style={{ maxWidth: "500px", margin: "0 auto" }}>
                 <div
                     style={{
                         display: "flex",
                         alignItems: "center",
                         justifyContent: "center",
                     }}
                 >
                     <Tabs
                         defaultActiveKey="community"
                         size={"large"}
                         items={items}
                         onChange={(value) => {
                             handleChangeRoute(value);
                         }}
                     />
                 </div>
                 <div
                     style={{
                         marginTop: "50px",
                         display: "flex",
                         alignItems: "center",
                         justifyContent: "center",
                     }}
                 >
                     <Outlet />
                 </div>
             </div>
         </>
     );
 }
 

4.2 登录组件的应用测试

Login登录组件,一个简单的小Demo来测试路由正确性,他不会被权限组件<PrivateRoute/>包裹,可以随意进入

代码语言:typescript
复制
 import { Button } from "antd";
 import React from "react";
 import { setToken } from "../../tools/auth";
 import { useNavigate } from "react-router-dom";
 
 export default function Login() {
     const navigator = useNavigate();
     const handleLogin = () => {
         const preToken: object = {
             token: "hjsdbvfjhysebfjkd762354",
             expired: Date.now(),
         };
         console.log(JSON.stringify(preToken));
 
         setToken(JSON.stringify(preToken)); //模拟设置token
         navigator(`/`);
     };
 
     const handleRush = () => {
         navigator(`/`); //模拟强行进入主页
     };
     return (
         <div
             style={{
                 marginTop: "30px",
                 display: "flex",
                 alignItems: "center",
                 justifyContent: "center",
             }}
         >
             <Button
                 type={"primary"}
                 onClick={() => {
                     handleLogin();
                 }}
                 style={{ marginRight: "15px" }}
             >
                 登录进入系统主页
             </Button>
             <Button
                 type={"primary"}
                 onClick={() => {
                     handleRush();
                 }}
             >
                 强行进入系统主页
             </Button>
         </div>
     );
 }
 

5. 总结

本实践没有过多的文本描述,多在代码中的注释。但通过此个实践了解学习之后,应该可以较好的掌握在的React Hooks项目中应用Router V6封装整个项目的路由系统,能够真正实现一次封装,多处收益

相关的配套实践Demo会上传Github开源

项目链接:React Router V6项目中的路由鉴权封装实践(Hooks)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • React Router V6项目中的路由鉴权封装实践(Hooks)
    • 1. 前言
      • 1.1 路由封装的好处
      • 1.2 整体项目结构
    • 2. 前期准备工作
      • 2.1 安装依赖
      • 2.2 编写工具文件
      • 2.3 编写具体页面组件
    • 3. 路由组件的开发
      • 3.1 配置项目路由的根组件
      • 3.2 守卫路由的编写
      • 3.3 路由映射表的编写
      • 3.4 路由注册的编写
      • 3.5 路由渲染
    • 4. 组件内应用
      • 4.1 Layout组件应用测试
      • 4.2 登录组件的应用测试
    • 5. 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档