Ant Design Upload组件如何实现多文件同单次请求批量上传
Ant Design Upload 多选文件单请求上传解决方案
问题根因
你遇到的接口多次调用的核心原因有两个:
- Ant Design Upload 组件多选文件时,每个文件的状态变更都会独立触发
onChange回调,你将上传逻辑直接写在onChange里,就会被执行N次(N为选中文件数量) - 你的
formData没有在每次上传前重置,多次回调会导致文件重复追加到同一个FormData实例中
解决方法
方案1:选完文件立即自动单请求上传
如果需要选完文件立刻触发上传,只需要加防抖确保所有文件加载完成后,只执行一次上传逻辑,同时每次上传前新建FormData避免数据残留:
import { useRef, useState } from 'react'; import { Upload, UploadFile } from 'antd'; // 声明state存储选中的文件列表 const [selectedFiles, setSelectedFiles] = useState<UploadFile[]>([]); // 用ref存储防抖定时器,避免污染全局 const uploadTimerRef = useRef<NodeJS.Timeout | null>(null); const props = { multiple: true, showUploadList: false, beforeUpload: () => false, // 保留原有逻辑,阻止默认上传行为 onChange: (info: any) => { // 只保留状态为ready的有效文件 const validFiles = info.fileList.filter((file: any) => file.status === 'ready'); setSelectedFiles(validFiles); // 防抖处理:100ms内没有新文件添加,就触发上传 if (uploadTimerRef.current) clearTimeout(uploadTimerRef.current); uploadTimerRef.current = setTimeout(() => { handleUpload(validFiles); }, 100); }, }; // 单独封装上传逻辑 const handleUpload = (files: UploadFile[]) => { if (files.length === 0) return; setAttachmentLoader(true); // 每次上传新建FormData,避免历史数据残留 const formData = new FormData(); files.forEach((file: any) => { formData.append("upload2[]", file.originFileObj); }); formData.append("_charset_", "UTF-8"); formData.append("upload2-data", ""); uploadApiFunction(formData, (res: any) => { setAttachmentLoader(false); // 上传成功后清空选中文件 setSelectedFiles([]); res.text && message.success(res?.text, 4); }, (err: any) => { console.log(err); setAttachmentLoader(false); }); }; // 组件渲染部分 <Upload {...props} fileList={selectedFiles}> <PrimaryButton text="Add attachment" /> </Upload>
方案2:手动触发上传(更稳定)
如果允许用户选完文件后手动点击上传,逻辑会更简单,完全避免多次调用的问题:
import { useState } from 'react'; import { Upload, UploadFile, Button, message } from 'antd'; const [selectedFiles, setSelectedFiles] = useState<UploadFile[]>([]); const props = { multiple: true, showUploadList: true, // 可开启显示选中文件列表,方便用户确认 beforeUpload: () => false, onChange: (info: any) => { const validFiles = info.fileList.filter((file: any) => file.status === 'ready'); setSelectedFiles(validFiles); }, }; const handleManualUpload = () => { if (selectedFiles.length === 0) { message.warning('请先选择要上传的文件'); return; } setAttachmentLoader(true); const formData = new FormData(); selectedFiles.forEach((file: any) => { formData.append("upload2[]", file.originFileObj); }); formData.append("_charset_", "UTF-8"); formData.append("upload2-data", ""); uploadApiFunction(formData, (res: any) => { setAttachmentLoader(false); setSelectedFiles([]); res.text && message.success(res?.text, 4); }, (err: any) => { console.log(err); setAttachmentLoader(false); }); }; // 组件渲染部分 <> <Upload {...props} fileList={selectedFiles}> <PrimaryButton text="选择附件" /> </Upload> <Button type="primary" onClick={handleManualUpload} loading={attachmentLoader} style={{marginLeft: 16}} > 上传附件 </Button> </>
注意事项
- 每次上传前必须新建
FormData实例,不要复用全局的FormData,避免之前的文件残留导致重复上传 - 不要直接在
onChange里同步执行上传逻辑,多选时该回调会被每个文件触发一次 - 自动上传场景的防抖时长可根据实际情况调整,100-300ms都可以
内容的提问来源于stack exchange,提问作者lazyCoder
相关产品推荐
相关产品推荐

