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

react-hook-form中useFieldArray新增字段值重复异常原因解析

React Hook Form中useFieldArray的append/remove值残留问题解析

我在React Hook Form里用useForm和useFieldArray实现表单,把新增用户的初始值name和age设为undefined。但删除某个用户后再调用append添加新用户时,发现新用户的name和age不是预期的undefined,而是保留了之前被删除用户的值。把初始值改成null就正常了,想搞懂这个现象的内部逻辑,以及undefined会不会被默认值覆盖。

代码示例

import { uniqueId } from "lodash"
import { Controller, useFieldArray, useForm } from "react-hook-form"

// 预期新增值为undefined
const initialState = () => ({ id: uniqueId(), name: undefined, age: undefined })

const ReactHookForm = () => {
  const users = [
    {
      id: "1",
      name: "test1",
      age: 4,
    },
    {
      id: "2",
      name: "test2",
      age: 5,
    },
  ]

  const { control, handleSubmit } = useForm({ defaultValues: { users } })
  const { fields, append, remove } = useFieldArray({ control, name: "users" })

  return (
    <form className="mx-auto w-[50%]" onSubmit={handleSubmit((users) => console.log(users))}>
      <h1>RHF</h1>
      <button className="bg-[blue] text-[white]" type="button" onClick={() => append(initialState())}>
        append
      </button>
      {fields.map((user, i) => (
        <div key={user.id} className="mb-4 bg-white">
          <button className="bg-[red] text-[white]" type="button" onClick={() => remove(i)}>
            remove
          </button>
          <Controller
            control={control}
            name={`users.${i}.name`}
            render={({ field: { value, onChange } }) => (
              <div>
                <label className="w-[30%]">name</label>
                <input className="w-[70%]" type="text" value={value} onChange={onChange} />
              </div>
            )}
          />
          <Controller
            control={control}
            name={`users.${i}.age`}
            render={({ field: { value, onChange } }) => (
              <div>
                <label className="w-[30%]">age</label>
                <input className="w-[70%]" type="number" value={value} onChange={onChange} />
              </div>
            )}
          />
        </div>
      ))}
    </form>
  )
}

export default ReactHookForm

现象内部逻辑

React Hook Form的useFieldArray在处理字段数组时,是基于当前表单状态来合并新字段值的,而非完全替换。这里的核心是RHF对undefined的特殊处理逻辑:

  • 当你给append传的对象里包含undefined属性时,RHF会判定这些属性为「未定义」,不会主动覆盖表单内部对应路径已存在的值。
  • 删除用户后,表单状态里并没有彻底清除该索引位置的旧值缓存。当你再次append时,新对象里的undefined属性会被跳过,RHF直接复用之前该位置残留的旧值,导致看起来像是保留了删除用户的数据。

而null会被RHF视为明确的有效值,传入append时会主动覆盖对应位置的状态值,所以不会出现残留问题。

undefined的覆盖规则

在React Hook Form里:

  • undefined不会被当作有效的默认值来覆盖现有状态,RHF会跳过对undefined属性的赋值操作,保留当前状态中已有的值。
  • 只有传入null、字符串、数字这类明确的有效值时,才会覆盖表单状态里的对应字段。

如果要避免这个问题,除了把初始值改成null,也可以确保新增对象的属性使用明确的有效值,而非undefined。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 15:17:46