React Hook Form使用useController上传文件时file值为null解决方案
React Hook Form 配合 useController 实现文件上传配置方案
问题原因
你遇到的file字段始终为null的问题,本质是对文件输入框的特殊特性不熟悉,先解释官方文档那段说明的实际含义:
文件类型输入需要在应用层级管理,核心原因有两点:
- 文件输入选中内容后返回的是
FileList类型对象,不是普通文本/数字这类基础值,无法直接复用普通输入框的值绑定逻辑- 用户打开系统文件选择弹窗后可随时取消选择,这类边界场景的状态同步需要手动处理,表单库没法自动覆盖所有情况
你当前代码的核心错误有两个:
defaultValues里给file字段设置了空字符串""作为初始值,和后续要存储的File对象类型不匹配,会导致React Hook Form的值同步异常- 没有针对文件输入自定义取值逻辑,默认的表单绑定逻辑会读取
e.target.value,但文件输入的真实选中内容存在e.target.files属性下,根本不会被默认逻辑捕获
正确配置步骤
1. 修正表单初始值
把file字段的初始值从空字符串改为null,和后续存储的File类型兼容:
const methods = useForm({ defaultValues: { email: "", course: "Enginering", program: "B.tech", mobielNumber: "", dob: "", gender: "", cityName: "", state: "", file: null, // 单文件场景初始值设为null,多文件场景可设为空数组[] }, });
2. 用useController绑定文件输入时自定义onChange逻辑
注意文件输入的value属性是浏览器只读属性,绝对不要直接绑定field.value到input的value属性上,否则控制台会抛出非法赋值错误。单文件上传的绑定示例:
import { useController } from "react-hook-form"; function FileInput() { const { field } = useController({ name: "file", control: methods.control, rules: { required: "请上传必填文件" }, // 按需配置校验规则 }); return ( <input type="file" ref={field.ref} name={field.name} onBlur={field.onBlur} onChange={(e) => { // 手动从files属性取选中的第一个文件,同步给表单状态 const selectedFile = e.target.files?.[0] || null; field.onChange(selectedFile); }} // 按需配置accept属性限制文件类型,比如accept=".pdf,.doc,image/*" /> ); }
如果是多文件上传场景,只需要修改onChange里的取值逻辑即可:
onChange={(e) => { const selectedFiles = Array.from(e.target.files || []); field.onChange(selectedFiles); }}
3. 提交时的处理
提交表单时直接从values中取file字段即可,发multipart请求时把字段append到FormData对象中,不要手动序列化JSON,也不要手动设置请求的Content-Type头,浏览器会自动补全multipart/form-data对应的边界标识:
const onSubmit = (values) => { const formData = new FormData(); Object.entries(values).forEach(([key, val]) => { formData.append(key, val); }); // 直接把formData作为请求体发送即可 };
配置完成后,选中文件就能正常在表单值中拿到对应的File对象,不会再出现null的问题。
内容的提问来源于stack exchange,提问作者nishikant singh
相关产品推荐
相关产品推荐

