先记住这个答案
文件 input 的 value 不是可任意赋值的本地文件路径,网页不能借它指定用户设备上的任意文件。React 通常让该控件保持非受控,通过 onChange 的 currentTarget.files 或 ref 读取 FileList,再将选中的 File 对象和上传状态交给业务逻辑。应用可以控制文件列表展示、校验与上传流程,但不能把这些状态等同于用 value 持续控制浏览器的文件选择。
- 读取实际文件用 files,不解析 value 中的假路径
- 选中文件与上传成功是两个独立状态
- 清空 DOM 选择时也要按业务规则重置相关展示状态
value 为什么不是上传需要的文件内容
选择文件后,value 可能显示带有 fakepath 的字符串,它并不暴露真实本地路径,也不包含完整文件数据。多文件选择时,这个字符串也不能代表全部选择。真正需要遍历的是 files 中的 File 对象,再根据上传 API 的要求构造请求。
File 包含 name、size、type 等信息,并可通过浏览器 API 读取内容。type 与扩展名适合做前端提示,却不能证明文件内容可信。服务端仍需依据业务规则检查类型、大小和权限,不能因为前端设置了 accept 就默认收到的一定是合法文件。
读取后明确当前队列与浏览器选择的关系
在 onChange 中可以用 Array.from(event.currentTarget.files ?? []) 取得本次文件数组,然后决定是替换当前选择还是追加到待上传队列。追加时要定义如何处理同名文件、重复内容和总大小限制;仅凭文件名判断完全相同通常不够。
应用把 File 保存到 state 以展示文件名,并不意味着文件 input 变成普通受控字段。选择器仍由浏览器管理,上传进度、失败重试和已保存附件属于另外的业务状态。删除列表里的某项时,应同步更新真实待上传队列,避免界面已经移除但请求仍带上旧文件。
清空、再次选择与预览资源要配对管理
可以在明确操作中把文件 input 的 DOM value 设为空字符串来清空选择,或重置对应表单;不能给它设置任意非空路径。若希望用户再次选择同一文件也能触发新处理,可在合适阶段清空控件,但要先保留本次需要的 File 引用,避免读取时选择已经消失。
如果为本地预览创建了对象 URL,需要在不再使用时释放,预览、队列和网络任务也应各自有清楚生命周期。离开页面是否取消上传、已经成功的附件是否保留、失败后是否允许重试,都不是文件 input 自动解决的事情,需由产品流程明确。
容易答错的地方
- 把 file.name 放进 value 就能回填已上传文件
- 文件名只是元数据,不能重建浏览器对用户本地文件的读取授权。已有附件应通过服务端资源信息单独展示,重新选择本地文件则走新的用户选择流程。
- 选择器只显示 PDF,服务端就不用验证
- accept 是选择提示,调用者还可以绕过页面直接发送请求。服务端必须独立校验允许的内容与操作权限,前端检查主要改善反馈速度。
面试官还会怎么问?
FileList 可以直接当普通数组修改吗?
它不是普通可变数组接口。需要按应用规则排序、过滤或追加时,可以先转换为 File 数组,维护自己的队列;这与浏览器控件的原始选择列表要区分。
读取 input.value 为什么拿不到真实路径?
浏览器刻意不把真实设备路径暴露给网页,常用假路径形式避免泄漏目录信息。上传应使用 File 对象,不依赖猜测用户文件系统位置。
清空 input 会自动取消正在进行的上传吗?
不会,它只是改变控件选择。网络任务需要独立的取消机制;若请求已经到达服务端,还要根据服务端语义处理是否真正停止或删除已保存内容。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。