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

React页面跳转时无法检测页面离开事件的问题求助

React未保存修改警告:覆盖浏览器卸载与路由跳转场景

你的现有代码仅监听了beforeunload事件,这个事件只在浏览器刷新、关闭标签页这类页面卸载场景触发。React单页应用的路由跳转属于内部页面切换,不会触发浏览器卸载,所以需要额外添加路由导航拦截逻辑。

完整解决方案

1. 保留浏览器卸载监听(处理刷新/关闭标签页)

这部分你的原有代码可以直接保留,负责拦截浏览器层面的页面卸载操作:

useEffect(() => {
  const handleBeforeUnload = (e) => {
    if (hasUnsavedChanges) {
      e.preventDefault();
      e.returnValue = '';
      return e.returnValue;
    }
  };

  window.addEventListener('beforeunload', handleBeforeUnload);
  return () => window.removeEventListener('beforeunload', handleBeforeUnload);
}, [hasUnsavedChanges]);

2. 添加React路由跳转拦截(处理内部页面跳转)

根据你使用的React Router版本,选择对应的实现方式:

React Router v6(当前主流版本)

使用useNavigate的block方法拦截导航:

import { useNavigate } from 'react-router-dom';

// 在组件内部
const navigate = useNavigate();

useEffect(() => {
  const unblock = navigate((location) => {
    if (hasUnsavedChanges) {
      const shouldLeave = window.confirm('你有未保存的修改,确定要离开吗?');
      if (shouldLeave) {
        unblock(); // 解除拦截,允许跳转
        navigate(location);
      }
      return false; // 阻止跳转
    }
    return true; // 允许正常跳转
  });

  // 组件卸载时解除拦截
  return () => unblock();
}, [hasUnsavedChanges, navigate]);

React Router v5及以下版本

使用useHistory的block方法:

import { useHistory } from 'react-router-dom';

// 在组件内部
const history = useHistory();

useEffect(() => {
  const unblock = history.block((location) => {
    if (hasUnsavedChanges) {
      return '你有未保存的修改,确定要离开吗?';
    }
  });

  return () => unblock();
}, [hasUnsavedChanges, history]);

整合后的完整组件示例

import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

const EditableForm = ({ hasUnsavedChanges }) => {
  const navigate = useNavigate();

  // 拦截浏览器卸载(刷新/关闭标签页)
  useEffect(() => {
    const handleBeforeUnload = (e) => {
      if (hasUnsavedChanges) {
        e.preventDefault();
        e.returnValue = '';
        return e.returnValue;
      }
    };

    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => window.removeEventListener('beforeunload', handleBeforeUnload);
  }, [hasUnsavedChanges]);

  // 拦截React路由跳转
  useEffect(() => {
    const unblock = navigate((location) => {
      if (hasUnsavedChanges) {
        const shouldLeave = window.confirm('你有未保存的修改,确定要离开当前页面吗?');
        if (shouldLeave) {
          unblock();
          navigate(location);
        }
        return false;
      }
      return true;
    });

    return () => unblock();
  }, [hasUnsavedChanges, navigate]);

  return (
    <div>
      {/* 你的表单或可编辑内容 */}
    </div>
  );
};

export default EditableForm;

注意事项

  • 浏览器对beforeunload的提示文案有统一限制,无法完全自定义;window.confirm的文案可以自定义,但样式由浏览器控制。
  • 组件卸载时一定要解除路由拦截(调用unblock()),避免内存泄漏或影响其他页面逻辑。

内容的提问来源于stack exchange,提问作者Abdul Rehman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:05:33