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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 14:22:53