使用Zod验证react-file-base64图片时必填错误的解决方法
问题分析与解决
核心问题
- 返回值类型不匹配:当
react-file-base64设置multiple={false}时,onDone回调返回的是单个文件对象,但你的Zod验证规则一直在用files?.length、files?.[0]?.type这类数组操作,导致验证逻辑完全失效。 - 表单状态同步冲突:你同时混用了react-hook-form的
register和手动setSomething来管理featured_image的值,这会导致hook form内部的表单状态没有正确更新,Zod验证时拿到的就是undefined。
修复步骤
1. 调整Zod验证规则适配单个文件对象
把针对数组的验证逻辑改成单个对象的判断逻辑:
// 先定义单个文件的验证Schema const fileSchema = z.object({ name: z.string(), type: z.string().refine(type => ACCEPTED_IMAGE_TYPES.includes(type), { message: '.jpg, .jpeg, .png and .webp files are accepted.' }), size: z.string().refine(size => parseInt(size, 10) <= MAX_FILE_SIZE, { message: `Max file size is 5MB.` }), base64: z.string() }); // 整合到总Schema中 const schema = z.object({ blog: z.any({ required_error: "请输入博客内容,不能为空!!!" }), title: z.string().min(5, { message: "标题至少需要5个字符" }), reading_time: z.string({ required_error: "阅读时长为必填项" }), featured_image: fileSchema.refine(file => !!file, { message: '图片为必填项.' }), blog_cat: z.string({ required_error: "请选择博客分类" }).min(6, { message: "请选择博客分类" }), tags: z.any() });
2. 修复表单状态同步问题
不要同时使用register和手动setSomething,二选一即可:
方式一:完全依赖react-hook-form的表单状态
去掉手动setSomething,直接让react-file-base64更新hook form的值:
// 初始化form时传入Zod解析器 const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(schema) }); // 修改FileBase组件的使用方式 <FileBase type='file' multiple={false} onDone={(file: featured_image_types) => register('featured_image').onChange(file)} />
方式二:手动管理状态并同步到hook form
如果需要保留本地something状态,确保同步到hook form:
const { register, setValue, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(schema), defaultValues: { featured_image: something.featured_image } }); // onDone时同时更新本地状态和hook form状态 <FileBase type='file' multiple={false} onDone={(file: featured_image_types) => { const newSomething = { ...something, featured_image: file }; setSomething(newSomething); setValue('featured_image', file); }} />
3. 验证调试
修改Zod的refine调试代码,现在可以正确拿到文件对象:
featured_image: fileSchema.refine(file => { console.log(file, "现在可以正确获取文件对象了"); return true; })
额外注意点
- 确保
MAX_FILE_SIZE的单位和file.size匹配:你的featured_image_types里size是字符串类型,验证时要转成数字再比较(比如parseInt(file.size, 10))。 ACCEPTED_IMAGE_TYPES要填写正确的MIME类型,比如['image/jpeg', 'image/png', 'image/webp']。
内容的提问来源于stack exchange,提问作者LOKESH R
相关产品推荐
相关产品推荐

