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

如何使用Zod对嵌套数组中的details数组执行增删改操作

解决React Hook Form中嵌套数组(budgets.details)的操作问题

要操作budgets数组内部的details嵌套数组,核心是针对每个budgets项的索引,动态生成useFieldArray的路径,因为useFieldArray需要明确指定要操作的数组在表单结构中的位置。

实现步骤与代码示例

  1. 保留外层budgets数组的useFieldArray实例,用于操作顶层预算项:
const { fields: budgetFields, append: appendBudget, remove: removeBudget } = useFieldArray({
  control,
  name: 'budgets'
});

// 修正追加预算项的逻辑,满足Zod对details数组的min(1)要求
const handleAppendMainArray = () => {
  appendBudget({
    name: 'Nova diretriz',
    percent: 10,
    details: [{ description: 'Detalhe inicial', value: 0 }]
  });
};
  1. 遍历budgetFields时,为每个预算项创建对应的details数组的useFieldArray实例:
{budgetFields.map((budget, budgetIndex) => {
  // 动态指定嵌套数组路径:budgets.[索引].details
  const { fields: detailFields, append: appendDetail, remove: removeDetail } = useFieldArray({
    control,
    name: `budgets.${budgetIndex}.details`
  });

  return (
    <div key={budget.id} style={{ margin: '1rem 0', padding: '1rem', border: '1px solid #eee' }}>
      {/* 预算项的基础输入 */}
      <input
        {...register(`budgets.${budgetIndex}.name`)}
        placeholder="Nome da diretriz"
        style={{ marginRight: '0.5rem' }}
      />
      <input
        type="number"
        {...register(`budgets.${budgetIndex}.percent`)}
        placeholder="Porcentagem"
        style={{ marginRight: '0.5rem' }}
      />

      {/* 追加details的按钮 */}
      <button type="button" onClick={() => appendDetail({
        description: 'Novo detalhe',
        value: 0
      })}>
        + Adicionar Detalhe
      </button>

      {/* 渲染details列表 */}
      <div style={{ margin: '0.5rem 0 0 1rem' }}>
        {detailFields.map((detail, detailIndex) => (
          <div key={detail.id} style={{ margin: '0.5rem 0' }}>
            <input
              {...register(`budgets.${budgetIndex}.details.${detailIndex}.description`)}
              placeholder="Descrição do recurso"
              style={{ marginRight: '0.5rem' }}
            />
            <input
              type="number"
              {...register(`budgets.${budgetIndex}.details.${detailIndex}.value`)}
              placeholder="Valor"
              style={{ marginRight: '0.5rem' }}
            />
            <button type="button" onClick={() => removeDetail(detailIndex)}>
              Remover
            </button>
          </div>
        ))}
      </div>

      {/* 删除当前预算项 */}
      <button type="button" onClick={() => removeBudget(budgetIndex)} style={{ marginTop: '0.5rem' }}>
        Remover Diretriz
      </button>
    </div>
  );
})}

关键注意事项

  • 路径格式:必须使用点语法budgets.${budgetIndex}.details来指定嵌套数组的位置,确保useFieldArray能正确定位到目标数组。
  • Zod约束兼容:追加预算项时,必须给details数组传入至少一个初始元素,否则会触发Zod的min(1)校验错误。
  • 子组件优化:如果表单结构复杂,建议将单个预算项抽成独立子组件,把control和budgetIndex作为props传递,在子组件内部处理details数组的操作,让代码更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 09:42:46