React路由拦截器详解

在React中,路由拦截器是一种机制,用于在导航到特定路由之前执行一些逻辑,比如权限校验、用户认证或动态路由控制。通常,React使用react-router-dom库来管理路由,通过<Routes><Route>定义路由规则。

实现路由拦截的常见方式包括以下几种:


1. 使用<Navigate>实现重定向拦截

通过react-router-dom<Navigate>组件,可以在用户未通过权限校验时将其重定向到指定页面。

示例代码

import React from "react";
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";// 模拟认证状态
const isAuthenticated = false;// 路由守卫组件
const ProtectedRoute = ({ children }) => {return isAuthenticated ? children : <Navigate to="/login" />;
};const App = () => {return (<Router><Routes><Route path="/login" element={<Login />} /><Routepath="/dashboard"element={<ProtectedRoute><Dashboard /></ProtectedRoute>}/></Routes></Router>);
};const Login = () => <h2>登录页面</h2>;
const Dashboard = () => <h2>仪表板页面</h2>;export default App;

2. 使用useEffect在组件中拦截导航

可以在页面组件中使用useEffect处理路由进入的逻辑,比如权限检查或数据初始化。

示例代码

import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";const Dashboard = () => {const navigate = useNavigate();useEffect(() => {// 模拟权限检查const hasAccess = false;if (!hasAccess) {navigate("/login");}}, [navigate]);return <h2>仪表板页面</h2>;
};export default Dashboard;

3. 使用react-router的嵌套路由和Layout组件

通过在布局组件中统一处理路由拦截,可以实现更简洁的权限管理。

示例代码

import React from "react";
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet } from "react-router-dom";// 模拟认证状态
const isAuthenticated = false;// 布局组件
const ProtectedLayout = () => {return isAuthenticated ? <Outlet /> : <Navigate to="/login" />;
};const App = () => {return (<Router><Routes><Route path="/login" element={<Login />} /><Route element={<ProtectedLayout />}><Route path="/dashboard" element={<Dashboard />} /><Route path="/settings" element={<Settings />} /></Route></Routes></Router>);
};const Login = () => <h2>登录页面</h2>;
const Dashboard = () => <h2>仪表板页面</h2>;
const Settings = () => <h2>设置页面</h2>;export default App;

4. 中间件逻辑封装(高阶组件)

如果需要复用逻辑,可以封装为高阶组件(HOC)。

示例代码

import React from "react";
import { Navigate } from "react-router-dom";const withAuth = (Component) => {return (props) => {const isAuthenticated = false; // 模拟认证状态return isAuthenticated ? <Component {...props} /> : <Navigate to="/login" />;};
};const Dashboard = () => <h2>仪表板页面</h2>;export default withAuth(Dashboard);

总结

  • 小型项目:可以直接在组件内使用useNavigate<Navigate>处理路由跳转。
  • 中型项目:推荐使用布局组件(如<Outlet>)统一管理路由拦截。
  • 大型项目:封装高阶组件(HOC)或自定义Hook,结合reduxcontext进行权限状态管理。

根据具体需求选择合适的实现方式!

案例:

import React, { useCallback, useEffect, useMemo, useState } from "react";
import { getMenuParentKey } from "@/utils";
import { useDidRecover } from "react-router-cache-route"
import Error from "@pages/err";
import { Spin } from "antd";
import { useLocation } from "react-router-dom";
import { useDispatchLayout, useDispatchMenu, } from "@/store/hooks";const scrollPage = () => {window.scrollTo({top: 0,left: 0,behavior: "smooth",});
}const fallback = <Spin style={{display: "flex",alignItems: "center",justifyContent: "center",minHeight: 500,fontSize: 24,
}} tip="页面加载中...." />function Intercept({ menuList, components: Components, [MENU_TITLE]: title, [MENU_PATH]: pagePath, [MENU_KEEPALIVE]: isKeep, pageKey, [MENU_LAYOUT]: layout, ...itemProps }) {const location = useLocation()const { stateAddOpenedMenu: addOpenedMenuFn, stateSetSelectMenuKey: setSelectedKeys, stateSetOpenMenuKey: setOpenKeys, stateSetCurrentPath: setPath } = useDispatchMenu()const { stateChangeLayout } = useDispatchLayout()const [pageInit, setPageInit] = useState(false)const currentPath = useMemo(() => {const { pathname, search } = locationreturn pathname + search}, [location])// 监听 location 改变const onPathChange = useCallback(() => {if (isKeep !== "true") {addOpenedMenuFn({ key: currentPath, path: currentPath, title: title || "未设置标题信息" });}}, [currentPath, title, isKeep, addOpenedMenuFn])const setCurrentPageInfo = useCallback(() => {if (!title) {return;}document.title = title;setSelectedKeys([String(pageKey)]);let openkey = getMenuParentKey(menuList, pageKey);setOpenKeys(openkey);addOpenedMenuFn({ key: currentPath, path: currentPath, title });}, [currentPath, menuList, title, pageKey, setOpenKeys, setSelectedKeys, addOpenedMenuFn])const init = useCallback(() => {setCurrentPageInfo()scrollPage()}, [setCurrentPageInfo])useEffect(() => {if (!pageInit) {init()setPageInit(true)}}, [init, pageInit])useEffect(() => {if (pageInit) {onPathChange()}}, [onPathChange, pageInit])// 切换布局useEffect(() => {layout && stateChangeLayout("push", layout)}, [layout, stateChangeLayout])// 路由改变useEffect(() => {setPath(currentPath)}, [currentPath, setPath])useDidRecover(() => {setPath(currentPath)init()}, [init, currentPath, setPath])const hasPath = !menuList.find((m) => (m[MENU_PARENTPATH] || "") + m[MENU_PATH] === pagePath);if (hasPath && pagePath !== "/" && pagePath !== "*") {return (<Error{...itemProps}status="403"errTitle="权限不够"subTitle="Sorry, you are not authorized to access this page."/>);}return (<Components{...itemProps}fallback={fallback}/>);
}
export default Intercept

这段代码定义了一个名为Intercept的React组件,核心作用是作为一个路由拦截器,完成以下任务:

  1. 初始化页面状态和路径管理

    • 设置页面标题、打开菜单、选中菜单、当前路径等信息。
    • 通过useEffectuseCallback处理组件的生命周期及路径变化。
  2. 权限检查

    • 检查当前路径是否有对应的菜单项。如果没有权限访问当前路径,返回一个错误组件,显示403页面。
  3. 页面布局切换

    • 动态切换页面布局(layout)。
  4. 路由恢复逻辑

    • 监听路由的切换和恢复事件(useDidRecover),以确保页面状态在路径切换后能够正确恢复。

核心功能分析

1. 页面初始化逻辑
  • 变量初始化

    const currentPath = useMemo(() => {const { pathname, search } = location;return pathname + search;
    }, [location]);
    
    • 使用useMemo监听location变化,动态计算当前完整路径。
  • 初次加载初始化

    useEffect(() => {if (!pageInit) {init();setPageInit(true);}
    }, [init, pageInit]);
    
    • 在组件首次渲染时,调用init函数完成页面初始化工作(如设置标题、菜单状态等)。
  • 路径变化监听

    useEffect(() => {if (pageInit) {onPathChange();}
    }, [onPathChange, pageInit]);
    
    • 当路径发生变化时,执行onPathChange更新已打开的菜单列表。
2. 权限检查
  • 核心逻辑
    const hasPath = !menuList.find((m) => (m[MENU_PARENTPATH] || "") + m[MENU_PATH] === pagePath
    );if (hasPath && pagePath !== "/" && pagePath !== "*") {return (<Error{...itemProps}status="403"errTitle="权限不够"subTitle="Sorry, you are not authorized to access this page."/>);
    }
    
    • 检查menuList中是否有匹配的路径:
      • 如果路径不合法(即未在menuList中找到对应项),则渲染403错误页面。
      • 排除根路径"/"和通配路径"*"
3. 动态布局切换
  • 布局切换逻辑
    useEffect(() => {layout && stateChangeLayout("push", layout);
    }, [layout, stateChangeLayout]);
    
    • 如果传入了layout属性,则调用stateChangeLayout方法切换布局模式。
4. 路由恢复支持
  • 恢复逻辑
    useDidRecover(() => {setPath(currentPath);init();
    }, [init, currentPath, setPath]);
    
    • 当路由恢复时,重新初始化页面状态并设置当前路径。

代码结构总结

1. 核心流程
  • 初始化阶段:通过init设置页面标题、菜单状态、路径信息,并首次渲染组件内容。
  • 路径变化监听:在useEffect中根据location变化更新状态。
  • 权限检查:验证路径是否存在于menuList,否则渲染403页面。
  • 布局切换:根据layout动态改变布局。
2. 关键点拆解
  • 性能优化
    • 使用useMemouseCallback优化重复计算和函数重建。
  • 状态管理
    • 集成了多个状态管理方法(如useDispatchMenuuseDispatchLayout)。
  • 用户体验
    • 自动恢复页面状态,确保路径变化后体验一致。
3. 代码模块化
  • 权限校验:独立实现逻辑,返回错误页面。
  • 状态管理:通过useDispatchsetState组合处理菜单、路径和布局等全局状态。

改进建议

  1. 增强代码可读性

    • 把复杂逻辑(如路径变化监听、权限检查)拆分成独立的工具函数,提高代码复用性和可维护性。
    • 添加注释解释每个核心逻辑。
  2. 减少依赖传递

    • 使用Context或Redux集中管理状态,减少从props中传递过多参数。
  3. 错误处理和提示优化

    • menuList为空或useDispatchMenu未初始化的情况进行额外的边界处理。
  4. 性能监控

    • 在路径变化频繁时,注意useEffect中逻辑是否存在性能瓶颈(如大量DOM操作或API调用)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/66488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、VSCODE 使用GIT插件

VSCODE 使用GIT插件 一下载git插件与git Graph插件二、git插件使用三、文件提交到远程仓库四、git Graph插件 一下载git插件与git Graph插件 二、git插件使用 git插件一般VSCode自带了git&#xff0c;就是左边栏目的图标 在下载git软件后vscode的git插件会自动识别当前项目 …

消息队列MQ(二)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 MQ学习笔记 前言一、发送者的可靠性1. 生产者重试机制2. 生产者确认机制3. 实现生产者确认 二、MQ的可靠性1. 数据持久化2. LazyQueue 前言 在用MQ实现异步调用时&#xff0…

数据分析思维(九):分析方法——AARRR模型分析方法

数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python&#xff0c;更重要的是数据分析思维。没有数据分析思维和业务知识&#xff0c;就算拿到一堆数据&#xff0c;也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》&#xff0c;本文内容就是提取…

【计算机网络】课程 实验四 配置快速生成树协议(RSTP)

实验四 配置快速生成树协议&#xff08;RSTP&#xff09; 一、实验目的 1&#xff0e;理解快速生成树协议RSTP的工作原理。 2&#xff0e;掌握如何在交换机上配置快速生成树。 二、实验分析与设计 【背景描述】 某学校为了开展计算机教学和网络办公&#xff0c;建立了一个计…

Tauri教程-基础篇-第一节 Tauri项目创建及结构说明

“如果结果不如你所愿&#xff0c;就在尘埃落定前奋力一搏。”——《夏目友人帐》 “有些事不是看到了希望才去坚持&#xff0c;而是因为坚持才会看到希望。”——《十宗罪》 “维持现状意味着空耗你的努力和生命。”——纪伯伦 Tauri 技术教程 * 第四章 Tauri的基础教程 第一节…

pyinstaller冻结打包多进程程序的bug:无限创建进程直至系统崩溃

前面写过两篇相关的文章&#xff1a; PyQt应用程序打包Python自动按键 这两篇文章都没有提到下面的这个重要问题&#xff1a; 采用Pyinstaller冻结打包多进程程序时&#xff0c;必须非常小心。这个技术线在Windows上会有一个非常严重的Bug。直接运行打包后的程序会造成无限创…

网络安全-kail linux 网络配置(基础篇)

一、网络配置 1.查看网络IP地址&#xff0c; 我的kail&#xff1a;192.168.15.128 使用ifconfig查看kail网络连接情况&#xff0c;ip地址情况 又复制了一台kail计算机的IP地址。 再看一下windows本机&#xff1a;使用ipconfig进行查看&#xff1a; 再看一下虚拟机上的win7I…

uni app 写的 小游戏,文字拼图?文字拼写?不知道叫啥

从下方的偏旁部首中选在1--3个组成上面文章中的文字&#xff0c;完成的文字标红 不喜勿喷 《满江红》 其中用到了两个文件 strdata.json parameters.json 这两个文件太大 放到资源中了 资源文件 <template><view class"wenzi_page_main"><view c…

分享几个高清无水印国外视频素材网站

在数字内容创作日益盛行的今天&#xff0c;高质量的视频素材成为了视频制作、广告创意和多媒体项目中不可或缺的元素。对于追求专业水准的创作者而言&#xff0c;高清、无水印的视频素材是确保作品质量的基石。以下将分享几个优质的视频素材网站&#xff0c;为您的创作之路提供…

【LLM】大语言模型基础知识及主要类别架构

文章目录 LLM大语言模型1.LLM基础知识1.1大模型介绍:1.2语言模型1.21n-gram语言模型1.22神经网络语言模型1.23基于Transformer的预训练语言模型1.24大语言模型 1.3模型评估指标1.31 BLEU1.32 Rouge指标1.33 困惑度PPL 2.LLM主要类别架构2.1 自编码模型2.2 自回归模型2.3 Encode…

剖析 Claim-Check 模式:以小传大,赋能分布式系统与微服务

1. 前言 1.1 写作背景与目的 在当今分布式系统与微服务架构盛行的时代&#xff0c;服务间的消息传递与数据交换越来越频繁。传统的消息传输在面对海量数据时&#xff0c;往往会遇到以下痛点&#xff1a; 消息体过大&#xff1a;直接通过消息队列或服务间接口发送大体量数据&…

【Uniapp-Vue3】v-if条件渲染及v-show的选择对比

如果我们想让元素根据响应式变量的值进行显示或隐藏可以使用v-if或v-show 一、v-show 另一种控制显示的方法就是使用v-show&#xff0c;使用方法和v-if一样&#xff0c;为true显示&#xff0c;为false则不显示。 二、v-if v-if除了可以像v-show一样单独使用外&#xff0c;还…

JVM实战—OOM的定位和解决

1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是&#xff1a;建立一套监控平台&#xff0c;比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台&#xff0c;就可以接入系统异常的监控和报警&#xff0c;可以设置当系统出现OOM异常&…

Idea(中文版) 项目结构/基本设置/设计背景

目录 1. Idea 项目结构 1.1 新建项目 1.2 新建项目的模块 1.3 新建项目模块的包 1.4 新建项目模块包的类 2. 基本设置 2.1 设置主题 2.2 设置字体 2.3 设置注释 2.4 自动导包 2.5 忽略大小写 2.6 设置背景图片 3. 项目与模块操作 3.1 修改类名 3.2 关闭项目 1. I…

liunx 中编写 springboot 服务停止时定时检查重启脚本

当服务内存溢出或其他一些原因&#xff0c;导致程序停止运行&#xff0c;服务不可用&#xff0c;为了服务能够及时自动重启&#xff0c;记录一下操作过程&#xff01; 首先编写自动重启的脚本指令&#xff0c;脚本在服务器上编写的&#xff0c;最后不要写好txt文件&#xff0c;…

CV-LLM经典论文解读|VTimeLLM: Empower LLM to Grasp Video MomentsVTimeLLM:赋能大语言模型理解视频片段

论文标题 VTimeLLM: Empower LLM to Grasp Video Moments VTimeLLM&#xff1a;赋能大语言模型理解视频片段 论文链接&#xff1a; VTimeLLM: Empower LLM to Grasp Video Moments论文下载 论文作者 Bin Huang, Xin Wang, Hong Chen, Zihan Song, Wenwu Zhu (Tsinghua Un…

wujie无界微前端框架初使用

先说一下项目需求&#xff1a;将单独的四套系统的登录操作统一放在一个入口页面进行登录&#xff0c;所有系统都使用的是vue3&#xff0c;&#xff08;不要问我为啥会这样设计&#xff0c;产品说的客户要求&#xff09; 1.主系统下载wujie 我全套都是vue3&#xff0c;所以直接…

ceph文件系统

ceph文件系统&#xff1a;高度可扩展&#xff0c;分布式的存储文件系统&#xff0c;旨在提高性能&#xff0c;高可靠性和高可用的对 象存储&#xff0c;块存储&#xff0c;文件系统的存储。使用分布式的算法保证数据的高可用和一致性。 ceph的组件 1、MON&#xff1a;ceph m…

Django的runserver

当年执行 python manage runserver命令时 1. 先执行 runserver 中的 handle方法 2. 执行 self.run()方法 3. 执行 self.inner_run() 3.1 inner_run 下 run方法的封装 3.1.1 接着看 handle 怎么来的 封装了一个方法 接着找返回函数 3.1.2在 basehttp 下 3.1.3 get_wsgi_appl…

开源AI智能名片2+1链动模式S2B2C商城小程序在商业流量获取中的应用研究

摘要&#xff1a; 随着互联网技术的迅猛发展&#xff0c;商业流量的获取已成为企业市场竞争中的关键环节。传统意义上的“客流量”在互联网语境下被赋予了新的内涵&#xff0c;即“商业流量”&#xff0c;其本质依然指向用户。在当前线上线下融合的商业环境中&#xff0c;流量…