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

RHF Field Array字段重复问题求助:输入时生成新UUID字段

React Hook Form Field Array 字段被重新创建问题

问题现象

使用RHF的Field Array功能时,填写字段数组中的字段会触发RHF用新UUID重建该字段;初始状态下filters是全为空字符串的对象数组,但输入内容后,值会被存入新生成的、所有属性为undefined的字段中。

代码问题分析

  1. 错误使用field.id作为数组索引
    代码中getValues('filters')[field?.id]是核心错误:filters是数组,只能用数字索引(0、1、2...)访问,而field.id是RHF生成的UUID字符串,用它访问数组会得到undefined,进而导致后续subFields判断异常,触发不必要的渲染逻辑,最终让RHF无法正确关联字段条目。

  2. Field命名不符合Field Array规范
    所有Field组件的name属性用了filters.${field.id}.xxx,但RHF的Field Array是基于数组索引管理的,应该使用filters.${index}.xxx来关联数组中的对应项,否则RHF会识别为新的独立字段,生成新UUID。

  3. 渲染周期内频繁调用getValues
    在fields.map中多次调用getValues会导致性能损耗,且容易获取到过期状态的值,应该用useWatch获取实时的表单值。

修正后的代码

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

const SegmentForm = () => {
  const { control, getValues } = useFormContext();
  const { fields, append, remove} = useFieldArray({
    control,
    name: 'filters'
  });
  // 用useWatch获取实时的filters数组
  const filters = useWatch({ control, name: 'filters' });

  return (
    <Stack gap={4} mt={2} mb={4}>
      <Field.Text name='name' label='Name' InputLabelProps={{ shrink: true }} />
      <Field.Text
        multiline
        name='description'
        label='Description'
        InputLabelProps={{ shrink: true }}
      />

      <Stack justifyContent='space-between' direction='row'>
        <Typography>Filters</Typography>
        <Button
          onClick={() =>
            append({
              field: '',
              operator: '',
              value: ''
            })
          }
          variant='contained'
          startIcon={<Iconify icon='mingcute:add-line' />}
        >
          New filter
        </Button>
      </Stack>

      {fields.map((field, index) => {
        // 用数组索引获取当前字段值
        const selectedField = filters[index]?.field;
        const subFields = FIELDS.find((e) => e.id === selectedField)?.values;

        return (
          <Stack key={field.id} spacing={4}>
            <Stack spacing={4} justifyContent='space-between' direction='row' alignItems='center'>
              {/* 用index构建Field的name */}
              <Field.Select name={`filters.${index}.field`} label='Field'>
                {FIELDS.map((option) => (
                  <MenuItem key={option.id} value={option.id}>
                    {option.label}
                  </MenuItem>
                ))}
              </Field.Select>
              {filters.length > 1 && (
                <Box>
                  <IconButton color='inherit' onClick={() => remove(index)}>
                    <Iconify icon='solar:trash-bin-trash-bold' />
                  </IconButton>
                </Box>
              )}
            </Stack>

            <Stack direction='row' spacing={4}>
              <Field.Select name={`filters.${index}.operator`} label='Operator'>
                {OPERATOR.map((option) => (
                  <MenuItem key={option.id} value={option.id}>
                    {option.label}
                  </MenuItem>
                ))}
              </Field.Select>
              {!subFields && (
                <Field.Text
                  name={`filters.${index}.value`}
                  label='Value'
                  InputLabelProps={{ shrink: true }}
                />
              )}
              {!!subFields?.length && (
                <Field.Select name={`filters.${index}.value`} label='Value'>
                  {subFields.map((option) => (
                    <MenuItem key={option.id} value={option.id}>
                      {option.label}
                    </MenuItem>
                  ))}
                </Field.Select>
              )}
            </Stack>
            {index !== filters.length - 1 && <Divider />}
          </Stack>
        );
      })}
    </Stack>
  );
};

关键修正点说明

  • 替换field.id为数组index来构建Field的name属性,让RHF正确关联数组中的对应条目,避免生成新UUID。
  • 使用useWatch获取实时的filters数组,替代渲染周期内频繁调用getValues,提升性能同时确保获取最新状态。
  • 所有依赖filters长度的判断,改用filters.length替代getValues('filters')?.length,保持状态一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 23:36:11