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

如何在react-router-dom v6的SPA中检测路由变化并提示未保存修改?

React Router v6 路由跳转时检测未保存表单修改并提示警告

在React Router v6中,要实现路由跳转前检测未保存表单修改并弹窗警告,可以通过以下几种方式实现:

方法一:使用官方 usePrompt 钩子(v6.4+)

这是最简便的方案,React Router v6.4及以上版本提供了usePrompt钩子,直接用于触发导航确认提示:

import { usePrompt } from 'react-router-dom';
import { useState } from 'react';

function FormComponent() {
  // 已有的未保存修改标记,表单变化时更新为true,保存/取消时设为false
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);

  // 监听表单输入,更新未保存状态
  const handleInputChange = () => {
    setHasUnsavedChanges(true);
  };

  // 保存表单后重置状态
  const handleSave = () => {
    // 执行保存逻辑
    setHasUnsavedChanges(false);
  };

  // 取消编辑重置状态
  const handleCancel = () => {
    // 重置表单逻辑
    setHasUnsavedChanges(false);
  };

  // 使用usePrompt,当hasUnsavedChanges为true时触发提示
  usePrompt({
    message: '你有未保存的修改,确定要离开当前页面吗?',
    when: hasUnsavedChanges
  });

  return (
    <form>
      {/* 表单元素 */}
      <input type="text" onChange={handleInputChange} />
      <button onClick={handleSave}>保存</button>
      <button onClick={handleCancel}>取消</button>
    </form>
  );
}

方法二:使用 useBlocker 实现自定义弹窗(v6.4+)

如果需要替换浏览器默认的确认框,用自定义模态组件,可以使用useBlocker钩子来手动控制导航流程:

import { useBlocker, useNavigation } from 'react-router-dom';
import { useState, useEffect } from 'react';
import CustomModal from './CustomModal'; // 自定义模态组件

function FormComponent() {
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
  const [showConfirmModal, setShowConfirmModal] = useState(false);
  const blocker = useBlocker(() => hasUnsavedChanges);
  const navigation = useNavigation();

  // 处理表单输入、保存、取消逻辑同方法一
  const handleInputChange = () => setHasUnsavedChanges(true);
  const handleSave = () => { /* 保存逻辑 */ setHasUnsavedChanges(false); };
  const handleCancel = () => { /* 重置逻辑 */ setHasUnsavedChanges(false); };

  useEffect(() => {
    // 当导航被拦截时,显示自定义模态框
    if (blocker.state === 'blocked') {
      setShowConfirmModal(true);
    }
  }, [blocker.state]);

  // 确认离开的逻辑
  const handleConfirmLeave = () => {
    setShowConfirmModal(false);
    blocker.reset(); // 重置拦截状态
    // 继续执行导航
    navigation.navigate(blocker.location.pathname);
  };

  // 取消离开的逻辑
  const handleCancelLeave = () => {
    setShowConfirmModal(false);
    blocker.abort(); // 终止导航
  };

  return (
    <>
      <form>
        <input type="text" onChange={handleInputChange} />
        <button onClick={handleSave}>保存</button>
        <button onClick={handleCancel}>取消</button>
      </form>
      <CustomModal
        isOpen={showConfirmModal}
        message="你有未保存的修改,确定要离开吗?"
        onConfirm={handleConfirmLeave}
        onCancel={handleCancelLeave}
      />
    </>
  );
}

方法三:适配React Router v6.4以下版本

如果你的项目使用v6.4之前的版本,可以通过navigate.block方法来实现拦截:

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

function FormComponent() {
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
  const location = useLocation();
  const navigate = useNavigate();

  // 表单逻辑同前
  const handleInputChange = () => setHasUnsavedChanges(true);
  const handleSave = () => { /* 保存逻辑 */ setHasUnsavedChanges(false); };
  const handleCancel = () => { /* 重置逻辑 */ setHasUnsavedChanges(false); };

  useEffect(() => {
    // 注册导航拦截
    const unblock = navigate.block((tx) => {
      if (hasUnsavedChanges) {
        const shouldLeave = window.confirm('你有未保存的修改,确定要离开吗?');
        if (shouldLeave) {
          unblock(); // 解除拦截
          tx.retry(); // 重试导航
        }
      } else {
        unblock(); // 无未保存修改,直接放行
      }
    });

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

  return (
    <form>
      <input type="text" onChange={handleInputChange} />
      <button onClick={handleSave}>保存</button>
      <button onClick={handleCancel}>取消</button>
    </form>
  );
}

关键注意点

  • 确保hasUnsavedChanges状态能准确反映表单的修改状态:表单输入变化时设为true,保存/取消操作完成后设为false。
  • 组件卸载时要清理拦截逻辑(上述示例中都通过useEffect的返回值实现了),避免内存泄漏。

内容的提问来源于stack exchange,提问作者Ilya Kruchinin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:15:11