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

如何为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>
  );
})}

关键注意事项

  1. 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" })
        })
      )
    });
    
  2. 字段名称一致性:FormField的name属性、form.register的字段名、Zod Schema的字段名必须完全匹配(比如steps[${i}].title)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:20:00