如何使用React Hook Form处理对象数组的表单输入与提交?
实现React Hook Form数组对象输入的方案
第一步:更新useForm默认值
先把PlanProduct的默认值改成包含3个空对象的数组,让表单初始化时就对应好三个条目:
const { control, handleSubmit, formState: { errors }, } = useForm({ defaultValues: { target: "", value: "", PlanProduct: [ { createdBy: "", createdDate: "" }, { createdBy: "", createdDate: "" }, { createdBy: "", createdDate: "" }, ], }, });
第二步:循环渲染数组项的输入字段
在表单里遍历固定长度的数组,为每个对象的createdBy和createdDate字段生成对应的Controller组件,注意字段名要使用数组索引的路径格式(比如PlanProduct[0].createdBy),React Hook Form会自动识别这种嵌套数组字段:
<form onSubmit={handleSubmit(onSubmit)}> {/* 原有的target字段 */} <Controller name="target" control={control} rules={{ required: "Cost is required" }} render={({ field: { onChange, onBlur, value, name, ref } }) => ( <TextField variant="outlined" placeholder="Cost" inputRef={ref} sx={{ backgroundColor: "ghostWhite", boxShadow: "0px 4px 4px rgba(0, 0, 0, 0.1)", height: "35px", display: "flex", alignItems: "start", justifyContent: "center", borderRadius: "20px", flexGrow: "1", color: "black", marginTop: "18px", width: { xs: "100%", md: "auto", }, "& .MuiOutlinedInput-root": { border: 0, boxShadow: "unset", width: "100%", }, "& .MuiInputBase-colorPrimary": { border: 0, boxShadow: "unset", }, "& .MuiOutlinedInput-input": { paddingTop: 0, paddingBottom: 0, display: "flex", alignItems: "center", border: "0", }, "& .MuiOutlinedInput-notchedOutline": { border: 0, }, "& .MuiInputLabel-root": { fontFamily: "Overpass", }, }} value={value} onChange={onChange} /> )} /> {/* 新增的PlanProduct数组输入字段 */} {Array.from({ length: 3 }).map((_, index) => ( <div key={index} style={{ marginTop: "18px", display: "flex", gap: "12px" }}> {/* createdBy输入框 */} <Controller name={`PlanProduct[${index}].createdBy`} control={control} rules={{ required: "Created By is required" }} render={({ field: { onChange, onBlur, value, ref } }) => ( <TextField variant="outlined" placeholder={`Product ${index + 1} - Created By`} inputRef={ref} sx={{ backgroundColor: "ghostWhite", boxShadow: "0px 4px 4px rgba(0, 0, 0, 0.1)", height: "35px", borderRadius: "20px", flexGrow: 1, "& .MuiOutlinedInput-root": { border: 0, boxShadow: "unset" }, "& .MuiOutlinedInput-notchedOutline": { border: 0 }, }} value={value} onChange={onChange} error={!!errors?.PlanProduct?.[index]?.createdBy} helperText={errors?.PlanProduct?.[index]?.createdBy?.message} /> )} /> {/* createdDate输入框 */} <Controller name={`PlanProduct[${index}].createdDate`} control={control} rules={{ required: "Created Date is required" }} render={({ field: { onChange, onBlur, value, ref } }) => ( <TextField variant="outlined" placeholder={`Product ${index + 1} - Created Date`} type="date" inputRef={ref} sx={{ backgroundColor: "ghostWhite", boxShadow: "0px 4px 4px rgba(0, 0, 0, 0.1)", height: "35px", borderRadius: "20px", flexGrow: 1, "& .MuiOutlinedInput-root": { border: 0, boxShadow: "unset" }, "& .MuiOutlinedInput-notchedOutline": { border: 0 }, }} value={value} onChange={onChange} error={!!errors?.PlanProduct?.[index]?.createdDate} helperText={errors?.PlanProduct?.[index]?.createdDate?.message} InputLabelProps={{ shrink: true }} /> )} /> </div> ))} {/* 提交按钮 */} <button type="submit" style={{ marginTop: "24px", padding: "8px 16px" }}> 提交 </button> </form>
关键细节说明
- 字段命名规则:React Hook Form通过
PlanProduct[0].createdBy这种路径识别数组中的嵌套字段,自动将输入值绑定到对应数组项的属性上。 - 错误处理:通过
errors?.PlanProduct?.[index]?.createdBy链式访问,可针对每个数组项的字段单独显示错误提示。 - 循环逻辑:用
Array.from({ length: 3 })生成固定长度数组,确保渲染3组输入框。
提交后的数据结构
表单提交时,onSubmit函数接收的参数会自动生成符合要求的数组结构:
const onSubmit = (data) => { console.log(data.PlanProduct); // 输出示例: // [ // { createdBy: "用户输入值1", createdDate: "2024-05-20" }, // { createdBy: "用户输入值2", createdDate: "2024-05-21" }, // { createdBy: "用户输入值3", createdDate: "2024-05-22" }, // ] };
内容的提问来源于stack exchange,提问作者Mohamed Nabil
相关产品推荐
相关产品推荐

