You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React 18.2函数组件内导航时如何阻止默认行为并触发未保存提示?

解决方法

你的问题出在:beforeunload 事件只负责处理页面刷新、关闭或者跳转到外部链接的情况,而 React Router 的内部路由跳转是客户端行为,不会触发这个事件,所以弹窗没反应。

要覆盖所有场景,得同时处理浏览器卸载和 React Router 的导航拦截。下面是完整代码:

import { useLocation, useParams, useNavigate, useBlocker } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { useEffect } from 'react';

const YourComponent = () => {
  const dispatch = useDispatch();
  const location = useLocation();
  const navigate = useNavigate();
  const { id } = useParams();

  // 拦截应用内路由跳转
  useBlocker((tx) => {
    if (!id) {
      if (window.confirm('您所做的更改可能未保存,确定要离开吗?')) {
        tx.proceed();
      } else {
        tx.abort();
      }
    } else {
      tx.proceed();
    }
  });

  // 处理页面刷新、外部跳转
  useEffect(() => {
    const handleBeforeUnload = (event) => {
      if (!id) {
        event.preventDefault();
        event.returnValue = '';
        return '';
      }
    };

    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => window.removeEventListener('beforeunload', handleBeforeUnload);
  }, [id]); // 依赖id,确保条件变化时更新监听

  return (
    // 你的组件内容
  );
};

export default YourComponent;

几个关键点:

  • useBlocker:React Router v6.4+ 自带的钩子,专门拦截客户端路由跳转。通过 tx.proceed() 允许跳转,tx.abort() 取消跳转。
  • 自定义提示:浏览器对 beforeunload 的文案有限制,没法直接设置自定义内容,但内部路由跳转可以用 window.confirm 显示你想要的提示。
  • 依赖更新:把 id 加到 useEffect 的依赖里,这样当 id 变化时,监听逻辑会自动更新。

如果你的 React Router 版本低于 v6.4,用下面的方式替代 useBlocker:

useEffect(() => {
  const unblock = navigate((tx) => {
    if (!id) {
      if (window.confirm('您所做的更改可能未保存,确定要离开吗?')) {
        tx.unblock();
        tx.retry();
      }
    }
  });
  return unblock;
}, [id, navigate]);

这样不管是刷新页面、跳外部链接还是内部路由跳转,只要未保存更改(这里用 !id 判断),都会弹出提示。

内容的提问来源于stack exchange,提问作者Muhammad Usman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:02:47