如何在react-hook-form中检测表单值是否修改并更新edited状态?
检测react-hook-form表单值是否偏离默认值并更新edited状态
我来分享几个实用的实现方案,都是项目里亲测好用的,帮你轻松搞定这个需求~
方案一:监听所有表单值,与默认值深度对比
核心思路是实时监听表单的所有字段值,和初始默认值做深度对比,只要两者不相等,就把edited状态设为true。
代码示例
import { useForm, watch } from 'react-hook-form'; import { useState, useEffect } from 'react'; import isEqual from 'lodash/isEqual'; // 用lodash的深对比函数更省心 function ProfileForm() { // 定义你的默认表单值 const defaultFormValues = { name: '', email: '', address: { street: '', city: '' }, hobbies: [] }; const { register, control } = useForm({ defaultValues: defaultFormValues }); const [edited, setEdited] = useState(false); // 监听所有表单字段的实时值 const currentFormValues = watch(control); useEffect(() => { // 对比当前值和默认值,不等则标记为已编辑 setEdited(!isEqual(currentFormValues, defaultFormValues)); }, [currentFormValues, defaultFormValues]); return ( <form> <input {...register('name')} placeholder="姓名" /> <input {...register('email')} type="email" placeholder="邮箱" /> <input {...register('address.street')} placeholder="街道" /> <input {...register('address.city')} placeholder="城市" /> <button type="button">添加爱好</button> <p className="status">表单是否已编辑: {edited ? '✅ 是' : '❌ 否'}</p> </form> ); }
注意事项
- 不想引入lodash的话,可以自己实现深对比函数(递归对比对象和数组的每一项),但lodash的
isEqual经过充分测试,用起来更稳妥。 - 如果默认值是从props传入的动态值,一定要把它放到
useEffect的依赖数组里,确保更新时能重新对比。
方案二:利用react-hook-form内置的dirtyFields状态
react-hook-form本身提供了dirtyFields这个内置状态,它会自动跟踪哪些字段被修改过。只要dirtyFields不是空对象,就说明有字段偏离了默认值。
代码示例
import { useForm } from 'react-hook-form'; import { useState, useEffect } from 'react'; function SettingsForm() { const defaultValues = { theme: 'light', notifications: true, language: 'zh-CN' }; const { register, formState: { dirtyFields } } = useForm({ defaultValues }); const [edited, setEdited] = useState(false); useEffect(() => { // 只要dirtyFields有内容,就标记为已编辑 setEdited(Object.keys(dirtyFields).length > 0); }, [dirtyFields]); return ( <form> <select {...register('theme')}> <option value="light">浅色</option> <option value="dark">深色</option> </select> <label> <input {...register('notifications')} type="checkbox" /> 开启通知 </label> <select {...register('language')}> <option value="zh-CN">中文</option> <option value="en-US">英文</option> </select> <p>表单是否已编辑: {edited ? '是' : '否'}</p> </form> ); }
优势说明
- 无需手动监听所有字段,react-hook-form自动跟踪修改状态,性能更优。
- 当用户把字段改回默认值时,该字段会从
dirtyFields中移除,edited状态也会自动变回false,完全符合“值偏离默认值才标记”的需求。
方案三:手动触发对比(适合非实时场景)
如果不需要实时检测,比如只在用户点击“保存”按钮前检查,可以直接用getValues获取当前表单值,再和默认值对比:
import { useForm } from 'react-hook-form'; import isEqual from 'lodash/isEqual'; function SubmitForm() { const defaultValues = { title: '', content: '' }; const { register, getValues } = useForm({ defaultValues }); const [edited, setEdited] = useState(false); const handleCheck = () => { const currentValues = getValues(); setEdited(!isEqual(currentValues, defaultValues)); }; return ( <form> <input {...register('title')} placeholder="标题" /> <textarea {...register('content')} placeholder="内容" /> <button type="button" onClick={handleCheck}>检查是否已编辑</button> <p>表单是否已编辑: {edited ? '是' : '否'}</p> </form> ); }
这个方案适合不需要实时反馈的场景,能减少不必要的渲染。
内容的提问来源于stack exchange,提问作者Bibek
相关产品推荐
相关产品推荐

