Next.js14+Shadcn/Zod/RHF用户表单:图片上传等问题求助
问题解决方案
1. 图片上传编码错误
原因
Django接收文件上传要求表单必须使用multipart/form-data编码,且提交数据必须是FormData对象而非JSON格式。若直接用JSON提交文件,后端无法识别为合法文件类型。
解决步骤
- 在表单上声明
encType="multipart/form-data" - 提交时将表单数据转换为
FormData对象传递,而非直接发送JSON
示例代码(ProfileForm.tsx):
import { useForm, setValue } from 'react-hook-form'; import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; const ProfileSchema = z.object({ avatar: z.instanceof(File).optional(), user_id: z.number(), // 其他字段定义 }); type ProfileFormData = z.infer<typeof ProfileSchema>; export function ProfileForm() { const { register, handleSubmit, setValue, formState: { errors } } = useForm<ProfileFormData>({ resolver: zodResolver(ProfileSchema), }); const onSubmit = async (data: ProfileFormData) => { const formData = new FormData(); formData.append('user_id', data.user_id.toString()); if (data.avatar) formData.append('avatar', data.avatar); // 其余字段依次添加到FormData中 await createProfile(formData); }; return ( <form onSubmit={handleSubmit(onSubmit)} encType="multipart/form-data"> <input type="file" ref={register('avatar').ref} onChange={(e) => { const file = e.target.files?.[0]; file && setValue('avatar', file); }} /> {/* 其他表单字段 */} <button type="submit">提交</button> </form> ); }
2. User ID类型不匹配问题
原因
表单提交时user_id被以字符串形式传递(比如输入框默认返回字符串),但Django后端期望接收数字类型主键,导致主键校验失败。
解决步骤
- 在Zod Schema中自动完成字符串到数字的转换
- 或在提交前手动转换类型
示例Zod Schema配置:
const ProfileSchema = z.object({ user_id: z.string().transform(val => parseInt(val, 10)), // 其他字段 });
或提交时手动转换:
formData.append('user_id', parseInt(data.user_id as unknown as string, 10).toString());
3. {...field}处理图片输入崩溃问题
原因
React Hook Form的field对象包含的value属性为字符串/数字类型,而文件输入的value是FileList类型,直接展开{...field}会触发类型冲突,导致应用崩溃。
解决步骤
- 不对文件输入直接使用
{...field},手动拆分处理ref和onChange - 通过
setValue手动更新表单中的文件值
示例代码:
<input type="file" ref={register('avatar').ref} onChange={(e) => { const file = e.target.files?.[0]; if (file) setValue('avatar', file); }} />
补充:createProfile.ts请求配置
确保请求不手动设置Content-Type,浏览器会自动根据multipart/form-data生成正确的请求头:
export async function createProfile(formData: FormData) { const res = await fetch('/api/profile', { method: 'POST', body: formData, // 无需手动设置Content-Type }); if (!res.ok) throw new Error('提交失败'); return res.json(); }
内容的提问来源于stack exchange,提问作者Sulejman
相关产品推荐
相关产品推荐

