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

React/Next.js路由前检测表单变更实现方案咨询

解决Next.js表单未提交时页面跳转的警告问题

没问题,我来帮你搞定这个跳转警告的问题!作为React新手,确实需要理清Next.js里两种不同的导航场景——浏览器原生的页面卸载(比如刷新、关标签)和Next.js的客户端内部跳转,咱们一步步来实现:

核心思路

我们需要三个关键步骤:

  1. 跟踪表单输入状态,判断用户是否有未提交的修改(即表单是否“脏”了)
  2. 处理浏览器原生的beforeunload事件,拦截刷新/关闭标签的操作
  3. 拦截Next.js的客户端导航(比如点击Link组件跳转),提示用户确认

修改后的Home页完整代码

import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import Header from "../components/header";

export default () => {
  // 跟踪表单输入值
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  // 标记表单是否有未提交的修改
  const isFormDirty = username !== '' || password !== '';
  
  const router = useRouter();

  // 处理表单提交
  const handleForm = (e) => {
    e.preventDefault();
    console.log("trigger");
    // 提交后重置表单状态,避免跳转时再弹出警告
    setUsername('');
    setPassword('');
  };

  // 处理浏览器原生的页面卸载(刷新、关闭标签)
  useEffect(() => {
    const handleBeforeUnload = (e) => {
      if (isFormDirty) {
        // 大多数浏览器会忽略自定义文本,显示默认提示,但必须返回非空字符串
        e.preventDefault();
        e.returnValue = '';
      }
    };

    window.addEventListener('beforeunload', handleBeforeUnload);
    // 组件卸载时移除事件监听
    return () => window.removeEventListener('beforeunload', handleBeforeUnload);
  }, [isFormDirty]); // 依赖isFormDirty,状态变化时重新绑定事件

  // 处理Next.js客户端内部导航
  useEffect(() => {
    const handleRouteChangeStart = (url) => {
      // 如果表单是脏的,且目标页面不是当前页(避免重复触发)
      if (isFormDirty && url !== router.asPath) {
        const confirmLeave = window.confirm('你有未提交的表单内容,确定要离开吗?');
        if (!confirmLeave) {
          // 取消导航
          router.events.emit('routeChangeError');
          throw '路由跳转已取消';
        }
      }
    };

    router.events.on('routeChangeStart', handleRouteChangeStart);
    // 组件卸载时移除事件监听
    return () => router.events.off('routeChangeStart', handleRouteChangeStart);
  }, [isFormDirty, router]);

  return (
    <>
      <Header />
      <h1>Home</h1>
      <form onSubmit={handleForm}>
        <input 
          type="text" 
          placeholder="Username" 
          value={username}
          onChange={(e) => setUsername(e.target.value)}
        />
        <input 
          type="password" 
          placeholder="Password" 
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
        <button type="submit"> Login </button>
      </form>
    </>
  );
};

代码解释

  1. 状态跟踪:用useState保存用户名和密码的输入值,通过isFormDirty判断用户是否输入了内容但未提交。
  2. beforeunload事件处理:当表单脏时,给window添加beforeunload监听,拦截浏览器的刷新/关闭操作。注意:现代浏览器大多会忽略自定义提示文本,显示浏览器默认的警告,但必须设置e.returnValue = ''才能触发警告。
  3. Next.js客户端导航拦截:通过useRouter监听routeChangeStart事件,当用户尝试跳转到其他页面时,用window.confirm提示用户。如果用户取消,就触发routeChangeError来终止导航。
  4. 表单提交后的状态重置:提交表单后清空输入值,确保后续跳转不会触发警告。

额外注意

  • 确保你的页面跳转是用Next.js的Link组件(比如<Link href="/about"><a>About</a></Link>),这样才会触发客户端导航拦截。如果用原生<a>标签,会走浏览器跳转,此时beforeunload事件会处理警告。
  • 组件卸载时一定要移除事件监听,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 21:42:33