如何为Shadcn/ui的FormFields数组处理错误提示
解决方案
核心问题分析
你遇到的重复显示问题,本质是把两个独立字段(title/date)塞进了同一个FormField上下文,导致错误提示和标签无法正确绑定到各自字段。Shadcn/ui的FormField基于React Context传递字段状态,一个FormField只能对应一个表单字段。
推荐方案:为每个字段单独创建FormField结构
将每个步骤的title和date分别用独立的FormField包裹,确保每个字段都有自己的FormItem、FormLabel、FormControl和FormMessage,错误提示会精准对应到各自字段,不会重复。
调整后的代码示例
<div className="mb-10"> <h2 className="mb-2 text-xl font-semibold"> Can you list the key steps you need to take? </h2> <div className="flex flex-col gap-2"> {stepFields.map((field, i) => ( <div key={field.id} className="flex gap-2 items-start"> {/* 删除按钮 */} <Button variant={"ghost"} onClick={() => removeStep(i)}> <LuTrash2 className="h-5 w-5" /> </Button> {/* 步骤标题字段 */} <FormField name={`steps[${i}].title`} control={form.control} render={({ field }) => ( <FormItem className="flex-1"> <FormLabel>Step {i + 1}</FormLabel> <FormControl> <Input {...field} placeholder="Enter step title" className="w-full bg-zinc-50 p-2" /> </FormControl> <FormMessage /> </FormItem> )} /> {/* 步骤日期字段 */} <FormField name={`steps[${i}].date`} control={form.control} render={({ field }) => ( <FormItem> <FormLabel>Due Date</FormLabel> <FormControl> <Input {...field} type="date" /> </FormControl> <FormMessage /> </FormItem> )} /> </div> ))} <Button variant={"secondary"} className="border" onClick={() => addStep({ title: "", date: "" })} type="button" > Add step </Button> </div> </div>
手动绑定字段的替代方案
如果不想依赖FormField的上下文,也可以手动通过react-hook-form的form.getFieldState获取字段状态,直接关联FormLabel和渲染错误信息:
{stepFields.map((field, i) => { const titleState = form.getFieldState(`steps[${i}].title`); const dateState = form.getFieldState(`steps[${i}].date`); return ( <div key={field.id} className="flex gap-2 items-start"> <Button variant={"ghost"} onClick={() => removeStep(i)}> <LuTrash2 className="h-5 w-5" /> </Button> <div className="flex w-full gap-2"> {/* 手动绑定标题字段 */} <div className="flex-1"> <FormLabel htmlFor={`step-title-${i}`}>Step {i+1}</FormLabel> <FormControl> <Input id={`step-title-${i}`} {...form.register(`steps.${i}.title`, { required: "Title is required" })} placeholder="Enter step title" className="bg-zinc-50 p-2" /> </FormControl> {titleState.error && <FormMessage>{titleState.error.message}</FormMessage>} </div> {/* 手动绑定日期字段 */} <div> <FormLabel htmlFor={`step-date-${i}`}>Due Date</FormLabel> <FormControl> <Input id={`step-date-${i}`} {...form.register(`steps.${i}.date`, { required: "Date is required" })} type="date" /> </FormControl> {dateState.error && <FormMessage>{dateState.error.message}</FormMessage>} </div> </div> </div> ); })}
关键注意事项
- Zod Schema 配置:确保表单Schema正确定义数组字段的验证规则,比如:
const formSchema = z.object({ steps: z.array( z.object({ title: z.string().min(1, "Title cannot be empty"), date: z.date({ required_error: "Please select a date" }) }) ) }); - 字段名称一致性:
FormField的name属性、form.register的字段名、Zod Schema的字段名必须完全匹配(比如steps[${i}].title)。
内容的提问来源于stack exchange,提问作者Niels Koop
相关产品推荐
相关产品推荐

