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

如何在React Router v3中阻止用户意外路由切换?

解决React Router v3中阻止意外路由切换及页面刷新的方案

嘿,我完全懂你现在的困扰——React Router v3里没有v4的<Prompt>组件,setRouteLeaveHook又管不了页面刷新这类浏览器层面的操作,别担心,我们可以把两个方法结合起来,完美覆盖所有意外跳转场景:

1. 处理路由内跳转(返回按钮、导航链接):用setRouteLeaveHook

在你需要阻止跳转的组件(比如有未保存表单的页面)里,在componentDidMount中调用setRouteLeaveHook,它能拦截React Router控制的所有路由切换行为:

componentDidMount() {
  // 保存路由钩子的清理函数,后续卸载组件时要用
  this.leaveHook = this.props.router.setRouteLeaveHook(
    this.props.route,
    this.handleRouteLeave
  );
}

handleRouteLeave = (nextLocation) => {
  // 判断是否有未保存内容,比如表单是否被修改过
  if (this.state.hasUnsavedChanges) {
    return '你有未保存的更改,确定要离开吗?';
  }
  // 没有未保存内容时,返回undefined或true就会允许正常跳转
};

2. 处理页面刷新/关闭标签页:监听beforeunload事件

浏览器原生的beforeunload事件可以捕获页面刷新、关闭标签页这类操作,我们同样在组件挂载时添加监听,卸载时记得移除:

componentDidMount() {
  // 上面的路由钩子代码...
  window.addEventListener('beforeunload', this.handleBeforeUnload);
}

componentWillUnmount() {
  // 清理路由钩子
  this.leaveHook();
  // 移除beforeunload事件监听,避免内存泄漏
  window.removeEventListener('beforeunload', this.handleBeforeUnload);
}

handleBeforeUnload = (e) => {
  if (this.state.hasUnsavedChanges) {
    // 注意:部分浏览器会忽略自定义文本,显示默认提示,但必须返回值才能触发确认框
    e.preventDefault();
    e.returnValue = '你有未保存的更改,确定要离开吗?';
    return e.returnValue;
  }
};

完整组件示例

把上面的逻辑整合到一个带表单的组件里,大概是这样:

import React, { Component } from 'react';

class EditableForm extends Component {
  state = {
    formData: { name: '' },
    hasUnsavedChanges: false,
  };

  componentDidMount() {
    // 设置路由离开钩子
    this.leaveHook = this.props.router.setRouteLeaveHook(
      this.props.route,
      this.handleRouteLeave
    );
    // 监听页面刷新/关闭事件
    window.addEventListener('beforeunload', this.handleBeforeUnload);
  }

  componentWillUnmount() {
    this.leaveHook();
    window.removeEventListener('beforeunload', this.handleBeforeUnload);
  }

  handleRouteLeave = (nextLocation) => {
    if (this.state.hasUnsavedChanges) {
      return '你有未保存的更改,确定要离开吗?';
    }
  };

  handleBeforeUnload = (e) => {
    if (this.state.hasUnsavedChanges) {
      e.preventDefault();
      e.returnValue = '你有未保存的更改,确定要离开吗?';
      return e.returnValue;
    }
  };

  handleInputChange = (e) => {
    const { name, value } = e.target;
    this.setState(prevState => ({
      formData: { ...prevState.formData, [name]: value },
      hasUnsavedChanges: true,
    }));
  };

  handleSave = () => {
    // 这里写你的保存逻辑(比如调用接口)
    this.setState({ hasUnsavedChanges: false });
  };

  render() {
    const { formData } = this.state;
    return (
      <div>
        <input
          name="name"
          value={formData.name}
          onChange={this.handleInputChange}
          placeholder="输入姓名"
        />
        <button onClick={this.handleSave}>保存</button>
      </div>
    );
  }
}

export default EditableForm;

小提醒

  • beforeunload的提示文本:不同浏览器可能会替换成自己的默认文案,但只要返回非空值,就能触发确认框。
  • 按需启用:只有当确实存在未保存内容时,才让钩子生效,不然每次跳转都弹提示会影响用户体验。
  • 清理工作:一定要在组件卸载时清理路由钩子和事件监听,避免内存泄漏问题。

内容的提问来源于stack exchange,提问作者chan wook

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:21:13