使用Shadcn Form、React-Hook-Form与Zod Resolver时,校验失败抛出Runtime ZodError而非在组件内显示错误
使用Shadcn Form、React-Hook-Form与Zod Resolver时,校验失败抛出Runtime ZodError而非在组件内显示错误
我之前也踩过类似的坑,你的代码逻辑看起来完全符合Shadcn和React-Hook-Form的规范,但错误没有被组件正确捕获反而抛出Runtime异常,大概率是版本兼容或者某个容易忽略的细节出了问题。下面给你拆解可能的原因和解决办法:
核心排查:版本兼容性问题
你的依赖版本组合里,zod^4.0.17是比较老旧的v4版本,而@hookform/resolvers^3.9.1是较新的解析器版本。两者的错误处理逻辑可能存在不匹配——旧版Zod抛出的错误格式,和新版resolver预期的捕获格式不一致,导致错误没有被转换成React-Hook-Form的内部错误状态,反而直接冒泡成了未捕获的Runtime异常。
解决起来很简单:把Zod升级到与当前resolver兼容的稳定版本,直接更到最新v4系列即可:
npm install zod@latest # 或 yarn add zod@latest
确认Form组件的错误绑定细节
虽然你的代码看起来没问题,但再核对几个关键细节:
FormMessage必须放在FormField的上下文范围内,你的代码已经做到了,它会自动读取当前字段的错误信息,这部分是正确的。- 确保
useForm的配置没有覆盖默认错误处理逻辑,比如不要手动开启可能导致错误溢出的特殊配置。
调整后的完整可运行代码
如果升级版本后还有问题,可以试试这个微调后的代码(核心逻辑和你的一致,主要是明确校验模式):
'use client'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Button } from '@/components/ui/button'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; const formSchema = z.object({ username: z.string().min(2, { message: 'Username must be at least 2 characters.', }), }); function TestPage() { // 定义表单,显式指定校验模式确保提交时才触发校验 const form = useForm<z.infer<typeof formSchema>>({ resolver: zodResolver(formSchema), defaultValues: { username: '', }, mode: 'onSubmit', }); // 仅接收校验通过的合法值 function onSubmit(values: z.infer<typeof formSchema>) { console.log('合法表单值:', values); } return ( <Form {...form}> <form className="space-y-8" onSubmit={form.handleSubmit(onSubmit)}> <FormField control={form.control} name="username" render={({ field }) => ( <FormItem> <FormLabel>Username</FormLabel> <FormControl> <Input placeholder="shadcn" {...field} /> </FormControl> <FormDescription> This is your public display name. </FormDescription> {/* 自动绑定当前字段的错误提示 */} <FormMessage /> </FormItem> )} /> <Button type="submit">Submit</Button> </form> </Form> ); } export default TestPage;
额外排查点
如果以上方法都无效,可以检查开发环境的其他配置:
- 是否开启了React严格模式?虽然不会直接导致错误抛出,但可以暂时关闭测试。
- 是否有全局错误捕获逻辑(比如自定义Error Boundary或第三方监控工具),把Zod的内部错误当成未捕获异常打印?这种情况下组件其实已经捕获了错误,只是全局逻辑又把它暴露了出来。
内容来源于stack exchange
相关产品推荐
相关产品推荐

