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

使用shadcn Select+react-hook-form时Zod接收undefined值问题求助

问题描述

在React项目中使用shadcn Select组件、react-hook-form表单库结合Zod做校验时,点击提交按钮出现以下问题:

  • 配置onSubmit={form.handleSubmit(onSubmitSearch)}时,Zod校验不通过,onSubmitSearch无法执行
  • 改为onSubmit={onSubmitSearch}后,onSubmitSearch能执行,但formSchema.parse({ ...e })报错,所有字段值均为undefined

错误信息:

Unhandled Runtime Error ZodError: [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["property_type"],
"message": "Required"
},
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["developer_id"],
"message": "Required"
},
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["location"],
"message": "Required"
}
]

问题原因
  • 字段名称不匹配:Zod Schema定义的字段是developer_id和location,但FormField的name属性写的是Developer和Location(名称、大小写都不对应),导致react-hook-form无法正确收集这两个字段的值,校验自然失败。
  • 错误获取表单值:直接解构表单事件e拿不到react-hook-form管理的表单数据,e是DOM提交事件对象,不是表单值集合,所以formSchema.parse({ ...e })必然拿不到有效数据。
  • Select组件绑定错误:shadcn的Select组件需要用value属性绑定field.value来同步表单状态,defaultValue仅在初始渲染生效,后续值更新不会同步到表单状态中。
修复方案

1. 修正FormField的name属性

将Developer改为developer_id,Location改为location,与Zod Schema保持完全一致:

// 修正developer_id字段的FormField
<FormField
  control={form.control}
  name="developer_id"
  render={({ field }) => (
    // 其余代码不变
  )}
/>

// 修正location字段的FormField
<FormField
  control={form.control}
  name="location"
  render={({ field }) => (
    // 其余代码不变
  )}
/>

2. 正确绑定Select组件的value属性

把Select的defaultValue替换为value,确保表单状态与组件值同步:

<Select
  onValueChange={field.onChange}
  value={field.value} // 替换defaultValue为value
>
  // 其余代码不变
</Select>

3. 恢复react-hook-form的标准提交逻辑

重新使用form.handleSubmit(onSubmitSearch),并直接使用react-hook-form传递的校验后数据(无需手动调用Zod parse,resolver已完成校验):

// 修正提交函数,直接接收校验后的data
const onSubmitSearch = (data) => {
  // 这里直接使用校验通过的表单数据
  console.log("提交数据:", data);
  // 编写你的业务提交逻辑
};

// 表单onSubmit改回标准写法
<form
  onSubmit={form.handleSubmit(onSubmitSearch)}
  className="mt-10 mb-8 flex flex-col md:flex-row justify-center md:space-x-3 w-fit max-w-fit mx-auto"
>
  // 其余代码不变
</form>

完整修正后的核心代码片段

const formSchema = z.object({
  property_type: z.string(),
  developer_id: z.string(),
  location: z.string()
});

const form = useForm({
  resolver: zodResolver(formSchema),
  defaultValues: {
    property_type: "",
    developer_id: "",
    location: ""
  }
});

const onSubmitSearch = (data) => {
  console.log("校验通过的提交数据:", data);
};

return (
  <Form {...form}>
    <form
      onSubmit={form.handleSubmit(onSubmitSearch)}
      className="mt-10 mb-8 flex flex-col md:flex-row justify-center md:space-x-3 w-fit max-w-fit mx-auto"
    >
      <div className="flex flex-col md:flex-row space-y-3 md:space-y-0 md:space-x-3 justify-evenly w-fit">
        <FormField
          control={form.control}
          name="property_type"
          render={({ field }) => (
            <FormItem>
              <Select
                onValueChange={field.onChange}
                value={field.value}
              >
                <FormControl>
                  <SelectTrigger className="py-1 px-2 rounded-md min-w-24 w-56 md:w-40 text-xs font-medium h-7 self-center">
                    <SelectValue placeholder="Property" />
                  </SelectTrigger>
                </FormControl>
                <SelectContent className="w-56 h-fit max-h-60 text-xs">
                  {/* 原有下拉内容不变 */}
                </SelectContent>
              </Select>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="developer_id"
          render={({ field }) => (
            <FormItem>
              <Select
                onValueChange={field.onChange}
                value={field.value}
              >
                <FormControl>
                  <SelectTrigger className="py-1 px-2 rounded-md min-w-24 w-56 md:w-40 text-xs font-medium h-7 self-center">
                    <SelectValue placeholder="Developer" />
                  </SelectTrigger>
                </FormControl>
                <SelectContent className="w-56 h-fit max-h-60 text-xs">
                  {/* 原有下拉内容不变 */}
                </SelectContent>
              </Select>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="location"
          render={({ field }) => (
            <FormItem>
              <Select
                onValueChange={field.onChange}
                value={field.value}
              >
                <FormControl>
                  <SelectTrigger className="py-1 px-2 rounded-md min-w-24 w-56 md:w-40 text-xs font-medium h-7 self-center">
                    <SelectValue placeholder="Location" />
                  </SelectTrigger>
                </FormControl>
                <SelectContent className="w-56 h-fit max-h-60 text-xs">
                  {/* 原有下拉内容不变 */}
                </SelectContent>
              </Select>
              <FormMessage />
            </FormItem>
          )}
        />
      </div>
      {/* 提交按钮部分不变 */}
    </form>
  </Form>
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:19:55