【react】实现路由返回拦截的多种方式

React路由拦截实现方案(React Router v5)

技术栈组合

# 核心依赖
react@17.x
react-dom@17.x
react-router-dom@5.3.4 
history@4.10.1
antd@4.24.8  # 用于弹框组件

方式一:使用history.block实现

import { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { Modal } from 'antd';function RouteGuard() {const history = useHistory();useEffect(() => {// 创建路由拦截器const unblock = history.block((tx) => {Modal.confirm({title: '离开确认',content: '有未保存的更改,确定要离开吗?',onOk: () => {unblock(); // 先解除拦截tx.retry(); // 重试跳转}});return false; // 阻止默认跳转});return () => unblock(); // 组件卸载时解除拦截}, [history]);return null;
}// 使用:在需要拦截的页面组件中引入

方式二:使用prompt结合message函数实现自定义弹框

import { Prompt } from 'react-router-dom';
import { Modal } from 'antd';let showModal = null;function CustomPrompt() {const [isBlocking, setIsBlocking] = useState(false);return (<><Promptwhen={isBlocking}message={(location) => {Modal.confirm({title: '路由拦截',content: `即将跳转到 ${location.pathname}`,onOk: () => setIsBlocking(false),onCancel: () => setIsBlocking(true)});return false; // 必须返回布尔值}}/></>);
}

方式三:自定义全局拦截器

基于prompt,修改路由getUserConfirmation实现自定义弹框拦截

// 入口文件index.js
import { BrowserRouter } from 'react-router-dom';
import { Modal } from 'antd';<BrowserRoutergetUserConfirmation={(message, callback) => {Modal.confirm({title: '系统提示',content: message,onOk: () => callback(true),onCancel: () => callback(false)});}}
><App />
</BrowserRouter>// 页面组件中使用
import { Prompt } from 'react-router-dom';function EditPage() {return (<Promptwhen={true}message="当前页面有未保存内容,确定离开?"/>);
}

方式四:动态路由控制

// 路由配置
const dynamicRoutes = [{path: '/dashboard',component: Dashboard,auth: true},{path: '/login',component: Login}
];// 路由守卫组件
function AuthRoute({ component: Component, ...rest }) {const isLogin = !!localStorage.getItem('token');return (<Route{...rest}render={(props) =>isLogin ? (<Component {...props} />) : (<Redirectto={{ pathname: '/login', state: { from: props.location } }}/>)}/>);
}// 动态路由渲染
function AppRouter() {return (<Switch>{dynamicRoutes.map((route) => (route.auth ? (<AuthRoute key={route.path} {...route} />) : (<Route key={route.path} {...route} />)))}</Switch>);
}

 方案对比

方案优势适用场景注意事项
方案一细粒度控制,支持复杂交互逻辑需要动态解除拦截的场景需手动管理拦截器生命周期
方案二组件化集成,简单快捷简单弹窗确认场景需要处理状态同步问题
方案三全局统一拦截策略,架构清晰需要统一拦截样式的项目需在入口文件配置
方案四完善的权限路由体系需要动态路由控制的企业级应用需维护路由配置元数据

最佳实践建议

混合使用策略:在大型项目中组合使用方案三(全局拦截)和方案四(权限路由)

性能优化:对于需要频繁拦截的页面,优先使用方案一(细粒度控制)

状态管理:建议配合Redux/Zustand管理路由拦截状态

异常处理:所有路由跳转需添加错误边界处理

TypeScript支持:推荐使用类型化的路由配置:

interface RouteConfig {path: string;component: React.ComponentType;auth?: boolean;children?: RouteConfig[];
}

扩展能力

埋点拦截:在路由守卫中添加用户行为追踪

history.listen((location) => {trackPageView(location.pathname);
});

页面缓存:结合<KeepAlive>实现路由级缓存

动态加载:配合React.lazy实现按需加载

const Dashboard = React.lazy(() => import('./Dashboard'));

多级路由守卫:实现全局守卫+页面级守卫的多层校验体系 

通过合理选择路由拦截方案,开发者可以在保证用户体验的同时,构建出安全可靠的前端路由系统。建议根据项目规模选择基础方案(中小项目用方案三)或组合方案(大型项目用方案三+四)

以上主要是用react router v5的方案

以下是react router v6

React路由拦截实现方案(React Router v5)

一、React Router v6适配要点

API变更说明

// v5 -> v6 核心变化
- <Switch> → <Routes>
- <Redirect> → <Navigate>
- useHistory → useNavigate
- withRouter移除,推荐使用Hooks

v6拦截方案示例

// 权限路由组件(v6版本)
const ProtectedRoute = ({ children }) => {const { user } = useAuth();const location = useLocation();return user ? children : (<Navigate to="/login" state={{ from: location }} replace />);
};// 路由配置
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>
} />
二、React Router v6数据加载API

Loader拦截示例

// 路由定义
const router = createBrowserRouter([{path: "/dashboard",element: <Dashboard />,loader: async () => {const data = await fetchUserData();if (!data.valid) throw new Response("Unauthorized", { status: 401 });return data;},errorElement: <ErrorPage />}
]);// 统一错误处理
<RouterProvider router={router} />
三、v6版本Prompt替代方案

自定义拦截逻辑

import { unstable_useBlocker as useBlocker } from 'react-router-dom';const NavigationBlock = ({ when }) => {useBlocker((tx) => {if (when && !window.confirm('确定离开当前页面?')) {tx.retry();}});return null;
};// 使用
<NavigationBlock when={formIsDirty} />
四、状态管理深度集成

Zustand集成示例

// store/authStore.js
import create from 'zustand';const useAuthStore = create(set => ({token: null,login: (token) => set({ token }),logout: () => set({ token: null })
}));// 路由组件
const AuthRoute = ({ children }) => {const token = useAuthStore(state => state.token);return token ? children : <Navigate to="/login" />;
};
五、增强型错误处理

异步操作拦截策略

const SaveBeforeLeave = () => {const blocker = useBlocker(({ currentLocation, nextLocation }) => currentLocation.pathname !== nextLocation.pathname);useEffect(() => {if (blocker.state === "blocked") {(async () => {try {await autoSave();blocker.proceed();} catch (error) {blocker.reset();}})();}}, [blocker]);
};
六、测试策略

Jest测试示例

test('拦截未授权访问', async () => {const TestComponent = () => {const nav = useNavigate();useEffect(() => { nav('/protected') }, []);return null;};render(<MemoryRouter><Routes><Route path="/protected" element={<ProtectedRoute><div>Protected</div></ProtectedRoute>} /><Route path="/login" element={<div>Login</div>} /></Routes><TestComponent /></MemoryRouter>);await waitFor(() => expect(screen.getByText('Login')).toBeInTheDocument());
});
七、TypeScript增强

完整类型定义

interface RouteMeta {requiresAuth?: boolean;permissions?: string[];
}declare module 'react-router-dom' {interface RouteObject {meta?: RouteMeta;children?: RouteObject[];}
}const routes: RouteObject[] = [{path: '/admin',element: <AdminPage />,meta: {requiresAuth: true,permissions: ['ADMIN']}}
];
八、安全增强措施

路由参数验证

const ProductRoute = () => {const { id } = useParams();const isValid = /^\d+$/.test(id);return isValid ? <ProductPage /> : (<Navigate to="/404" replace />);
};

升级路线图

版本核心方案升级建议
v5Prompt + 高阶组件逐步替换为v6方案
v6.0-6.3useBlocker实验性API配合状态管理实现
v6.4+数据路由 + Loader拦截推荐作为新项目首选方案

性能优化补充

代码分割

const Dashboard = lazy(() => import('./Dashboard'));
<Route path="/dashboard" element={<Suspense fallback={<Spinner />}><ProtectedRoute><Dashboard /></ProtectedRoute></Suspense>
} />

缓存策略

const CachedRoute = ({ children }) => {const elementRef = useRef(children);return <div hidden={!isVisible}>{elementRef.current}</div>;
};

移动端专项优化

手势拦截

useEffect(() => {const preventBack = (e) => {e.preventDefault();showConfirmModal();};history.pushState(null, '', window.location.pathname);window.addEventListener('popstate', preventBack);return () => window.removeEventListener('popstate', preventBack);
}, []);

离线处理

const NetworkAwareRoute = ({ children }) => {const [online] = useNetworkStatus();return online ? children : <OfflinePage />;
};

通过以上补充,路由拦截系统将具备:

  1. 版本兼容性:完整覆盖v5/v6双版本方案

  2. 类型安全:强化TypeScript类型支持

  3. 异常韧性:增强错误边界和异步处理

  4. 性能保障:代码分割与缓存策略优化

  5. 安全防护:参数验证与网络感知能力

  6. 测试覆盖:可验证的关键路径测试方

码字不易,大佬们点点赞呗

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

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

相关文章

k8s高可用集群安装

一、安装负载均衡器 k8s负载均衡器 官方指南 1、准备三台机器 节点名称IPmaster-1192.168.1.11master-2192.168.1.12master-3192.168.1.13 2、在这三台机器分别安装haproxy和keepalived作为负载均衡器 # 安装haproxy sudo dnf install haproxy -y# 安装Keepalived sudo yum …

node.js笔记

1. Node.js基本概念 1.1 什么是Node.js Node.js是一个开源、跨平台的JavaScript运行环境&#xff0c;广泛应用于各类项目。它基于Google Chrome的V8 JavaScript引擎&#xff0c;性能卓越。 Node.js在单个进程中运行&#xff0c;利用异步I/O操作避免阻塞&#xff0c;能高效处…

关于在vscode中的Linux 0.11 应用程序项目的生成和运行

首先我们需要需要查看镜像文件 查看软盘镜像文件 floppyb.img 中的内容 在 VSCode 的“Terminal”菜单中选择“Run Build Task...”&#xff0c;会在 VSCode 的顶部中间位置弹出一个 可以执行的 Task 列表&#xff0c;选择其中的“打开 floppyb.img”后会使用 Floppy Editor …

【JavaScript 简明入门教程】为了Screeps服务的纯JS入门教程

0 前言 0-1 Screeps: World 众所不周知&#xff0c;​Screeps: World是一款面向编程爱好者的开源大型多人在线即时战略&#xff08;MMORTS&#xff09;沙盒游戏&#xff0c;其核心机制是通过编写JavaScript代码来控制游戏中的单位&#xff08;称为“Creep”&#xff09;&#…

【CSS文字渐变动画】

CSS文字渐变动画 HTML代码CSS代码效果图 HTML代码 <div class"title"><h1>今天是春分</h1><p>正是春天到来的日子&#xff0c;花都开了&#xff0c;小鸟也飞回来了&#xff0c;大山也绿了起来&#xff0c;空气也有点嫩嫩的气息了</p>…

【论文阅读】基于思维链提示的大语言模型软件漏洞发现与修复方法研究

这篇文章来自于 Chain-of-Thought Prompting of Large Language Models for Discovering and Fixing Software Vulnerabilities 摘要 软件安全漏洞在现代系统中呈现泛在化趋势&#xff0c;其引发的社会影响日益显著。尽管已有多种防御技术被提出&#xff0c;基于深度学习&…

SpringMVC_day02

一、SSM 整合 核心步骤 依赖管理 包含 SpringMVC、Spring JDBC、MyBatis、Druid 数据源、Jackson 等依赖。注意点&#xff1a;确保版本兼容性&#xff08;如 Spring 5.x 与 MyBatis 3.5.x&#xff09;。 配置类 SpringConfig&#xff1a;扫描 Service 层、启用事务管理、导入…

基于ADMM无穷范数检测算法的MIMO通信系统信号检测MATLAB仿真,对比ML,MMSE,ZF以及LAMA

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 ADMM算法 4.2 最大似然ML检测算法 4.3 最小均方误差&#xff08;MMSE&#xff09;检测算法 4.4 迫零&#xff08;ZF&#xff09;检测算法 4.5 OCD_MMSE 检测算法 4.6 LAMA检测算法 …

CSS动画

目录 一、核心概念与语法 1. keyframes 关键帧 2. animation 属性 二、动画调速函数&#xff08;animation-timing-function&#xff09; 1. 预设值 2. 贝塞尔曲线 3. 步进函数&#xff08;steps()&#xff09; 三、动画控制与交互 1. 暂停与恢复 2. JavaScript 控制…

架构思维:预约抢茅子架构设计

文章目录 案例&#xff1a;预约抢茅子复杂度分析商品预约阶段等待抢购阶段商品抢购阶段订单支付阶段 技术方案商品预约阶段一、基于 Redis 单节点的分布式锁方案1. 核心流程2. 关键设计点 二、Redis 单节点方案的局限性1. 单点故障风险2. 主从切换问题 三、多节点 Redis 实现高…

PHP大马的使用

BestShell/best_php_shell.php at master Kevil-hui/BestShell 这里用到的是这位师傅的大马&#xff08;主要是从头开始写一个大马实在太麻烦了&#xff09; 用pikachu靶场进行上传的测试 在这里传马&#xff0c;这个是简单的前端校验&#xff0c;bp抓包改后缀就好了 上传成…

HCI 清除 SCP纳管残留信息

项目场景&#xff1a; 一台测试HCI主机&#xff0c;之前有连接了SCP&#xff0c;由于环境变更&#xff0c;无法与SCP连通&#xff0c;HCI残留了SCP纳管信息 问题描述 集群管理中没有脱离SCP的选项 点击vmware 虚拟机 显示被接管 云安全中心也显示被接管 原因分析&#xff1a; …

【算法day22】两数相除——给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。

29. 两数相除 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断为 8 &#x…

顺序表(C语言源码详解,附加测试代码)

目录 顺序表的基本实现 顺序表结构 顺序表的初始化 检查顺序表容量空间 顺序表的头插 顺序表的打印 顺序表的头删 顺序表的尾插 顺序表的尾删 顺序表的查找 ​编辑指定位置之前插入数据 指定位置删除数据 顺序表的销毁 顺序表的基本实现 顺序表结构 对顺序表的数…

draw.io费的思维导图软件、支持ProcessOn无水印导出。

draw.io的官方网址是 https://www.drawio.com/ 通过官方下载&#xff0c;本文只是安装及使用教程。 一、从别的思维导图软件导出并导入到Draw.io&#xff0c;&#xff08;ProcessOn为例&#xff09; 选择要付费下载流程图&#xff0c;并以ViSio格式导出&#xff08;后缀名…

springboot启动事件CommandLineRunner使用

什么是CommandRunner CommandRunner是springboot启动完成时会调用的一个runner 启动参数会传递到这个runner 我们能用来做一些初始化工作和缓存预热等工作 ApplicationRunner VS CommandRunner? 这两个Runner作用一样 只是得到的启动参数格式不一样 前者是一个Argument对象…

能源革命新突破:虚拟电厂赋能微电网智能调控,构建低碳生态新格局

在“双碳”目标的引领下&#xff0c;中央一号文件明确提出了“推进农村能源革命&#xff0c;深化绿色低碳技术应用”。作为能耗集中区域&#xff0c;产业园区如何实现清洁能源高效消纳与碳减排的目标成为了难题&#xff0c;中电国为推出的虚拟电厂与风光储充柴多能互补的微电网…

LabVIEW FPGA与Windows平台数据滤波处理对比

LabVIEW在FPGA和Windows平台均可实现数据滤波处理&#xff0c;但两者的底层架构、资源限制、实时性及应用场景差异显著。FPGA侧重硬件级并行处理&#xff0c;适用于高实时性场景&#xff1b;Windows依赖软件算法&#xff0c;适合复杂数据处理与可视化。本文结合具体案例&#x…