React路由切换时如何实现自定义确认提示?
React Router 全局路由切换确认提示实现方案
原代码问题分析
- 原生
Link组件的默认跳转行为不会被onClick中的逻辑阻止,即使用户取消确认,路由依然会跳转 - 每个
Link都需要单独绑定处理函数,无法实现全局统一拦截
方案一:自定义全局确认跳转组件(推荐)
创建一个封装了确认逻辑的自定义ConfirmLink组件,项目中所有路由跳转都使用这个组件,实现全局统一控制:
import { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import LoadingBar from "react-top-loading-bar"; // 自定义确认跳转组件 const ConfirmLink = ({ to, children, ...props }) => { const navigate = useNavigate(); const handleClick = (e) => { // 阻止Link的默认跳转行为 e.preventDefault(); // 弹出确认框 const isConfirm = confirm("确定要切换路由吗?"); if (isConfirm) { // 用户确认后手动导航 navigate(to); } }; return ( <Link to={to} onClick={handleClick} {...props}> {children} </Link> ); }; // 使用示例 export default function Demo() { const [progress, setProgress] = useState(0); return ( <> <LoadingBar color="blue" progress={progress} onLoaderFinished={() => setProgress(0)} waitingTime={800} loaderSpeed={100} height={4} /> <ul style={{ display: "flex", justifyContent: "space-around", listStyle: "none" }} > <li> <ConfirmLink to="/" onClick={() => setTimeout(() => setProgress(100), 500)} > Home </ConfirmLink> </li> <li> <ConfirmLink to="/about" onClick={() => setTimeout(() => setProgress(100), 500)} > About </ConfirmLink> </li> </ul> </> ); }
方案二:全局拦截所有路由跳转(包括编程式导航)
如果需要拦截所有路由跳转行为(包括通过navigate方法的编程式跳转),可以将以下逻辑放在全局路由组件(如App.js)中:
import { useState, useEffect } from "react"; import { Link, useLocation, useNavigate, useNavigation } from "react-router-dom"; import LoadingBar from "react-top-loading-bar"; export default function Demo() { const [progress, setProgress] = useState(0); const location = useLocation(); const navigate = useNavigate(); const navigation = useNavigation(); // 记录上一次路由地址,用于取消导航时回退 const [prevLocation, setPrevLocation] = useState(location); useEffect(() => { // 当导航状态变为"loading"时,说明正在跳转路由 if (navigation.state === "loading" && location !== prevLocation) { const isConfirm = confirm("确定要切换路由吗?"); if (!isConfirm) { // 用户取消,导航回上一次路由 navigate(prevLocation); } } // 更新上一次路由地址 setPrevLocation(location); }, [navigation.state, location, prevLocation, navigate]); return ( <> <LoadingBar color="blue" progress={progress} onLoaderFinished={() => setProgress(0)} waitingTime={800} loaderSpeed={100} height={4} /> <ul style={{ display: "flex", justifyContent: "space-around", listStyle: "none" }} > <li> <Link to="/" onClick={() => setTimeout(() => setProgress(100), 500)} > Home </Link> </li> <li> <Link to="/about" onClick={() => setTimeout(() => setProgress(100), 500)} > About </Link> </li> </ul> </> ); }
内容的提问来源于stack exchange,提问作者Sougata Mukherjee
相关产品推荐
相关产品推荐

