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

React Hook Form映射数组字段如何实现单字段独立校验

问题背景

需要基于对象数组批量生成表单字段,基于React Hook Form的Controller组件实现校验逻辑,渲染Material UI的TextField组件。
目前已实现带唯一值的字段渲染、空值阻止提交的基础逻辑,但存在校验错误全局触发的问题:只要任意一个条目字段为空,所有条目下的字段都会显示错误状态,期望错误仅在具体出错的单个字段上展示。

现有实现代码:

interface IItem {
  name: string
  quantity: number
  price: number
  total: number
}

interface IFormInput {
  name: string
  email: string
  items: IItem[]
}

const { control, handleSubmit, formState: { errors } } = useForm<IFormInput>()

const handleFormSubmit: SubmitHandler<IFormInput> = (data) => {
  console.log(data)
}

const data = {
  name: 'john doe',
  email: 'johndoe@mail.com',
  items: [
    { name: 'Banner Design', quantity: 1, price: 150, total: 150 },
    { name: 'Email Design', quantity: 2, price: 200, total: 400 },
  ],
}
return (
  <form onSubmit={handleSubmit(handleFormSubmit)}>
    {/* 姓名、邮箱字段Controller */}

    {data.items.map((item, index) => (
      <Controller
        name={`items.${index}.name`}
        control={control}
        defaultValue={item.name}
        rules={{
          required: "can't be empty",
        }}
        render={({ field }) => (
          /* 无法正确访问 errors.items.${index}.name 对应错误 */
          <FormControl error={!!errors.items}>
            <InputLabel>Item Name</InputLabel>
            <TextField {...field} />
          </FormControl>
        )}
      />

      {/* quantity、price、total字段Controller */}

    ))}

    <Button type='submit'>Submit</Button>

  </form>
)
问题原因

错误判断逻辑使用!!errors.items,只要items数组下存在任意校验错误,该表达式就会返回true,导致所有行的表单项都被标记为错误状态,没有精确匹配当前索引下的具体字段错误。

修复方案
  1. 错误状态判断需要精确到对应索引的对应字段,通过可选链逐层安全访问嵌套错误对象即可,TypeScript环境下也不会报类型错误。
  2. 可以同时把错误提示文本绑定到TextField的helperText属性,直接展示对应字段的校验提示。

修复后的字段渲染代码:

{data.items.map((item, index) => (
  <Controller
    name={`items.${index}.name`}
    control={control}
    defaultValue={item.name}
    rules={{
      required: "can't be empty",
    }}
    render={({ field }) => {
      // 精确匹配当前字段的错误对象
      const fieldError = errors.items?.[index]?.name;
      return (
        <FormControl error={!!fieldError}>
          <InputLabel>Item Name</InputLabel>
          <TextField 
            {...field} 
            error={!!fieldError}
            helperText={fieldError?.message}
          />
        </FormControl>
      )
    }}
  />

  {/*
    quantity、price、total字段逻辑完全一致,仅需修改错误访问路径的末尾字段名即可
    例:quantity字段错误取 errors.items?.[index]?.quantity
  */}
))}

如果觉得逐层写可选链比较繁琐,也可以直接导入React Hook Form提供的get工具方法,通过路径字符串直接取对应字段的错误,效果和可选链访问完全一致:

import { get } from 'react-hook-form';

// 在render函数中使用
const fieldError = get(errors, `items.${index}.name`);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 13:57:13