react-hook-form如何检测表单未保存变更并在返回时弹出提示
你需要的未保存变更判断标识其实已经在你解构的formState属性中了,就是isDirty字段:它的定义是表单当前值和初始化传入的defaultValues是否存在差异,刚好匹配你要的「是否有未提交修改」的判断需求。
不同场景的实现方案
场景1:自定义返回按钮的点击拦截
直接在返回按钮的点击回调中增加判断逻辑即可,示例代码如下:
const handleBack = () => { // 存在未保存修改时弹出提示 if (isDirty) { const confirmLeave = window.confirm("表单存在未保存的变更,确定要离开吗?"); // 用户选择不离开则终止逻辑 if (!confirmLeave) return; } // 此处写原有的返回逻辑,例如路由回退、关闭弹窗等 navigate(-1); }
场景2:拦截浏览器后退、刷新、关闭标签页行为
如果需要拦截浏览器原生的页面退出行为,可以监听beforeunload事件,在组件挂载时注册监听,卸载时移除即可:
import { useEffect } from 'react'; // ...其他代码 useEffect(() => { const handleBeforeUnload = (e) => { if (isDirty) { e.preventDefault(); // 部分浏览器需要设置returnValue才会弹出提示 e.returnValue = "表单存在未保存的变更,确定要离开吗?"; return e.returnValue; } }; window.addEventListener('beforeunload', handleBeforeUnload); // 组件卸载时移除事件监听,避免内存泄漏 return () => window.removeEventListener('beforeunload', handleBeforeUnload); }, [isDirty]);
场景3:拦截单页应用前端路由跳转(以React Router v6为例)
如果是单页应用,还需要拦截路由库的内部跳转逻辑,可以用对应路由库提供的拦截钩子,React Router v6可以用useBlocker实现:
import { useBlocker } from 'react-router-dom'; // ...其他代码 // 当isDirty为true时拦截路由跳转,弹出提示 useBlocker(() => { if (isDirty) { return window.confirm("表单存在未保存的变更,确定要离开吗?"); } return false; });
注意事项
- 表单提交成功后如果需要重置
isDirty状态,调用reset()方法即可,会将表单状态重置为初始的defaultValues,isDirty会自动变为false - 如果提交后需要更新默认比对基准为最新的表单值,可以给
reset传入新的默认值:reset(newFormValues),后续isDirty会以新传入的值作为比对标准
内容的提问来源于stack exchange,提问作者Majed Badawi
相关产品推荐
相关产品推荐

