React Hook Form使用useFieldArray时append触发isDirty为true如何解决
问题根因
formState.isDirty的底层判断逻辑是当前表单全量值与初始化时传入的defaultValues是否完全相等。你调用append新增字段后,表单内test数组的长度从4变为5,整体值已经和初始默认值不一致,所以会自动标记为脏,这是React Hook Form的默认行为。
解决方案
你可以根据业务场景选择以下两种实现方式:
方案1:自定义提交状态判断(推荐,无副作用)
不依赖原生isDirty,自行判断是否存在用户主动修改的内容:
- 提前把初始默认值存为独立常量
- 监听表单值,对比判断是否有非默认的修改内容
- 用自定义的判断结果控制提交按钮的禁用状态
核心改动逻辑:
// 提前存储初始默认值 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,后续只有用户主动修改字段值才会标记为脏:
- 从
useForm中解构出reset、getValues方法 - 调用
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
相关产品推荐
相关产品推荐

