上传多张图片时Zod验证失败:预期数组却收到对象的问题求助
解决Zod验证错误及实现图片上传流程
问题根源
你手动维护了tourImages状态却未同步到React Hook Form(RHF)的表单状态中,导致RHF拿到的values.images是input原生的File对象而非数组,与Zod Schema要求的数组类型冲突,触发Expected array received object错误。同时,表单阶段的images是File数组,但Zod Schema验证的是最终提交的string类型URL数组,类型不匹配也会引发验证失败。
解决方案步骤
1. 统一用RHF管理表单状态,移除自定义useState
删除独立维护的tourImages状态,改用RHF的setValue同步文件数组到表单字段:
import { useForm, SubmitHandler } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; // 表单输入阶段Schema:验证上传的File数组 const createTourFormSchema = z.object({ // 其他表单字段(如title、description等)按需添加 images: z.array(z.instanceof(File)), }); // 提交后端阶段Schema:验证最终的URL数组 const createTourSubmitSchema = z.object({ // 其他字段与表单Schema保持一致 images: z.array(z.string()), }); type ICreateTourFormInput = z.infer<typeof createTourFormSchema>; export const TourCreateForm = () => { const { register, handleSubmit, setValue } = useForm<ICreateTourFormInput>({ resolver: zodResolver(createTourFormSchema), defaultValues: { images: [], // 其他字段默认值 }, }); // 处理图片选择事件 const handleImagesChange = (event: React.ChangeEvent<HTMLInputElement>) => { const files = event.target.files; if (files) { const fileList = Object.values(files) as File[]; // 同步文件数组到RHF的images字段 setValue("images", fileList); } };
2. 修正表单输入组件的绑定
将RHF的register props传递给自定义FormInput,确保RHF能跟踪字段变化:
<FormInput name="images" labelText="Tour Images" type="file" multiple={true} onChange={handleImagesChange} {...register("images")} // 关键:绑定RHF注册器 />
3. 调整提交逻辑,先上传图片再提交数据
从RHF的values中获取File数组,上传到Cloudinary拿到URL数组后,构造符合后端要求的数据提交:
const onSubmitHandler: SubmitHandler<ICreateTourFormInput> = async (values) => { const uploadedImageUrls: string[] = []; // 批量上传图片到Cloudinary for (const image of values.images) { const imageFormData = new FormData(); imageFormData.append("file", image); imageFormData.append( "upload_preset", import.meta.env.VITE_CLOUDINARY_UPLOAD_PRESET ); try { const imageUploadRes = await uploadImage(imageFormData); const imageUrl = (imageUploadRes as any)?.data?.secure_url; if (imageUrl) uploadedImageUrls.push(imageUrl); } catch (err) { console.error("图片上传失败:", err); // 按需添加错误提示逻辑 return; } } // 构造最终提交给后端的数据 const submitData = { ...values, imageCover: imageCoverUrl, // 确保imageCoverUrl是已上传的封面图URL images: uploadedImageUrls, }; // 可选:用提交Schema验证最终数据 const validation = createTourSubmitSchema.safeParse(submitData); if (!validation.success) { console.error("提交数据验证失败:", validation.error); return; } // 调用RTK mutation提交数据 await createTour(submitData); };
4. 绑定提交函数到表单
确保表单的onSubmit绑定到RHF的handleSubmit:
<form onSubmit={handleSubmit(onSubmitHandler)}> {/* 其他表单字段 */} <FormInput {.../* 图片输入组件的props */} /> <button type="submit">创建旅行</button> </form>
关键说明
- 拆分Zod Schema为表单输入Schema和提交Schema,分别适配File数组和URL数组的验证需求
- 所有表单字段状态统一由RHF管理,避免自定义状态与RHF状态不一致的问题
- 图片上传过程中添加错误捕获,可按需调整为单张失败后继续上传其他图片
内容的提问来源于stack exchange,提问作者Ayush
相关产品推荐
相关产品推荐

