使用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
相关产品推荐
相关产品推荐

