Next.js14+Zod+shadcn/ui+React Hook Form多复选框实现问题
解决多选复选框字符串数组的Zod与React Hook Form配置问题
核心问题分析
你的Zod Schema reservationMethod: z.string().array() 本身是正确的,但表单实现有两处关键错误:
handleCheckboxChange未正确通过React Hook Form的field.onChange更新字段值- 错误地将
reservationMethod字段的props绑定到了"Name of agency"输入框,导致字段类型冲突(数组 vs 字符串)
修正后的完整实现
1. 调整Zod Schema(按需添加校验)
如果需要用户至少选一个选项,可添加.nonempty()校验;若可选则保留原写法:
import { z } from "zod"; const formSchema = z.object({ reservationMethod: z.string().array().nonempty("请选择至少一种预订方式"), // 可选:非空校验 agencyName: z.string().optional(), // 新增代理名字段,对应独立输入框 });
2. 修正表单组件代码
移除自定义的handleCheckboxChange,直接通过field.onChange更新数组,同时将输入框拆分为独立字段:
import { FormField, FormItem, FormLabel, FormControl } from "@/components/ui/form"; import { Checkbox } from "@/components/ui/checkbox"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; // 在Form组件内部: <FormField name="reservationMethod" control={form.control} render={({ field }) => ( <FormItem className="flex flex-col gap-4"> <FormLabel className="text-base md:text-lg text-black font-extralight"> Which of the following did you use to make your reservation? </FormLabel> <FormControl> <div className="flex gap-4 flex-wrap"> {/* 用数组统一管理选项,减少重复代码 */} {[ { id: "tourOperator", label: "Tour Operator", value: "Tour Operator" }, { id: "internet", label: "Internet", value: "Internet" }, { id: "directlyWithResort", label: "Directly with the resort", value: "Directly with the resort" }, { id: "travelAgent", label: "Travel Agent", value: "Travel Agent" }, ].map((option) => ( <div key={option.id} className="flex items-center gap-1"> <Checkbox id={option.id} checked={field.value.includes(option.value)} onCheckedChange={(checked) => { // 选中则添加值,取消则移除值 if (checked) { field.onChange([...field.value, option.value]); } else { field.onChange(field.value.filter(val => val !== option.value)); } }} /> <Label htmlFor={option.id}>{option.label}</Label> </div> ))} </div> </FormControl> </FormItem> )} /> {/* 代理名字段拆分为独立FormField */} <FormField name="agencyName" control={form.control} render={({ field }) => ( <FormItem className="flex items-center gap-2 mt-4"> <FormLabel className="text-base text-black font-extralight">Name of agency:</FormLabel> <FormControl> <Input type="text" {...field} placeholder="请输入代理名称" /> </FormControl> </FormItem> )} />
3. 确保表单初始值正确
创建表单时,给reservationMethod设置空数组初始值,匹配Zod的array类型:
import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { reservationMethod: [], agencyName: "", }, });
关键说明
- 完全通过React Hook Form的
field.value和field.onChange管理复选框状态,确保表单状态一致 - 每个输入项对应独立表单字段,避免类型冲突
- 用数组映射渲染复选框,简化代码维护
内容的提问来源于stack exchange,提问作者Aidan Mc Intosh
相关产品推荐
相关产品推荐

