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

使用React Hook Form与React Server Actions提交数组字段的问题

解决React Hook Form数组字段通过Form Action提交时扁平化的问题

你遇到的问题根源在于:HTML原生表单提交的FormData只会保留扁平的键值对,不会自动将services.0.id这类带点分隔的键解析成嵌套数组结构。而react-hook-form的handleSubmit在onSubmit模式下会自动处理结构化数据,但Form Action接收的是原始FormData,所以需要手动做转换处理。

方案1:手动解析FormData为结构化对象

写一个工具函数,把FormData中的扁平键转换成嵌套的数组/对象:

function formDataToObject(formData) {
  const obj = {};
  formData.forEach((value, key) => {
    const keys = key.split('.');
    let current = obj;
    for (let i = 0; i < keys.length; i++) {
      const k = keys[i];
      if (i === keys.length - 1) {
        current[k] = value;
      } else {
        // 识别数组索引格式,初始化数组结构
        if (!isNaN(Number(keys[i+1]))) {
          current[k] = current[k] || [];
          current = current[k];
          const index = parseInt(keys[++i], 10);
          current[index] = current[index] || {};
          current = current[index];
        } else {
          current[k] = current[k] || {};
          current = current[k];
        }
      }
    }
  });
  return obj;
}

然后修改你的handleFormSubmit函数:

const handleFormSubmit = async (input: FormData) => {
  // 转换FormData为结构化对象
  const formDataObj = formDataToObject(input);
  // 此时formDataObj中的services已转为数组格式
  const res = await createProposal.mutateAsync(formDataObj);

  if (!res.success) {
    toast.error(res.error?.message);
    return;
  }

  toast.success("Proposal successfully created");
  props.closeModal();
};

方案2:直接用react-hook-form的getValues()获取结构化数据

既然已经使用了react-hook-form,更简便的方式是直接调用getValues()拿到已结构化的表单数据,跳过FormData解析步骤:

首先确保你的form实例包含getValues:

const { control, register, setValue, handleSubmit, getValues, formState: { errors } } = useSlyderzForm(createProposalSchema, {
  title: "",
  services: [{ id: 1 }]
});

然后修改handleFormSubmit:

const handleFormSubmit = async () => {
  // 直接获取结构化的表单数据
  const formData = getValues();
  const res = await createProposal.mutateAsync(formData);

  if (!res.success) {
    toast.error(res.error?.message);
    return;
  }

  toast.success("Proposal successfully created");
  props.closeModal();
};

同时修改form标签的action属性:

<form
  id="create-proposal-form"
  action={() => handleFormSubmit()}
  className="space-y-8 overflow-auto"
>

注意事项

  • 方案2更贴合react-hook-form的设计逻辑,避免手动解析的繁琐
  • 如果表单包含文件上传,可保留FormData,同时用getValues()获取数组字段后合并到FormData中

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:32:09