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

React Hook Form使用useFieldArray时append触发isDirty为true如何解决

问题根因

formState.isDirty的底层判断逻辑是当前表单全量值与初始化时传入的defaultValues是否完全相等。你调用append新增字段后,表单内test数组的长度从4变为5,整体值已经和初始默认值不一致,所以会自动标记为脏,这是React Hook Form的默认行为。

解决方案

你可以根据业务场景选择以下两种实现方式:

方案1:自定义提交状态判断(推荐,无副作用)

不依赖原生isDirty,自行判断是否存在用户主动修改的内容:

  1. 提前把初始默认值存为独立常量
  2. 监听表单值,对比判断是否有非默认的修改内容
  3. 用自定义的判断结果控制提交按钮的禁用状态

核心改动逻辑:

// 提前存储初始默认值
const INITIAL_DEFAULT = {
  test: Array(4).fill({ firstName: "Bill", lastName: "Luo", canDelete: false })
}

function App() {
  const { register, control, handleSubmit, watch } = useForm({
    defaultValues: INITIAL_DEFAULT
  });
  const testValue = watch('test')
  // 自定义判断是否有用户修改
  const isAllowSubmit = () => {
    // 对比前4条初始数据是否被修改
    for(let i=0; i<4; i++) {
      if (testValue[i]?.firstName !== INITIAL_DEFAULT.test[i].firstName 
        || testValue[i]?.lastName !== INITIAL_DEFAULT.test[i].lastName) {
          return true
      }
    }
    // 对比新增数据是否有非空修改
    for(let i=4; i<testValue.length; i++) {
      if (testValue[i]?.firstName !== '' || testValue[i]?.lastName !== '') {
        return true
      }
    }
    return false
  }

  // 其余代码保持不变,提交按钮直接用自定义判断
  return (
    // ...其余代码
    <input type="submit" disabled={!isAllowSubmit()} />
  )
}

方案2:新增字段后更新默认值(代码改动最小)

调用append后同步更新表单的默认值,让原生isDirty恢复为false,后续只有用户主动修改字段值才会标记为脏:

  1. 从useForm中解构出reset、getValues方法
  2. 调用append后,把最新的表单值设为新的默认值,同时重置脏状态

核心改动逻辑:

const { register, control, handleSubmit, formState, reset, getValues } = useForm({
  defaultValues: {
    test: [
      { firstName: "Bill", lastName: "Luo", canDelete: false },
      { firstName: "Bill", lastName: "Luo", canDelete: false },
      { firstName: "Bill", lastName: "Luo", canDelete: false },
      { firstName: "Bill", lastName: "Luo", canDelete: false }
    ]
  }
});

// append按钮的点击逻辑修改
<button
  type="button"
  onClick={() => {
    const newItem = { firstName: "", lastName: "", canDelete: true };
    append(newItem);
    // 更新默认值,重置脏状态
    reset(
      { test: [...getValues("test")] },
      { keepDirty: false }
    );
  }}
>
  append
</button>

如果需要兼容删除字段的场景,在remove调用后也执行同样的reset逻辑即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 06:15:04