Ant Design Dragger组件多文件上传:onChange多次触发致重复文件问题
解决Ant Design Dragger多文件上传时onChange多次触发导致重复上传的问题
问题原因
Ant Design的Upload组件(包括Dragger)开启multiple后,每添加一个文件就会触发一次onChange事件。你的代码在每次onChange中都会遍历处理所有未上传的文件,后续的onChange调用会重复处理之前已经上传过的文件,最终造成重复上传。
解决方案
方案1:用beforeUpload阻止自动上传,手动收集文件后一次性提交
这种方式完全由自己控制上传流程,更可控:
- 修改
beforeUpload,返回false阻止组件自动上传,同时收集选中的文件:
const [pendingFiles, setPendingFiles] = useState([]); const beforeUpload = (file) => { setPendingFiles(prev => [...prev, file]); return false; };
- 新增手动上传逻辑,在合适时机(比如用户点击确认按钮)执行:
const handleManualUpload = async () => { try { // 过滤已上传的文件 const needUpload = pendingFiles.filter(file => !fileUploaded.find(x => x.name === file.name)); for await (const file of needUpload) { const typeMedia = file.type.split('/')[0]; const nameOnCloud = typeMedia === "video" ? `videos/${file.name + v4()}` : `images/${file.name + v4()}`; const storageRef = ref(storage, nameOnCloud); await uploadBytes(storageRef, file); try { const link = await getDownloadURL(storageRef); setFileUploaded(prev => [...prev, { name: file.name, link: link, nameOnCloud: nameOnCloud, type: typeMedia }]); } catch (error) { console.error('获取下载链接失败:', error); } } // 上传完成后清空待上传队列,更新展示列表 setPendingFiles([]); setFileList(prev => [...prev, ...needUpload.map(file => ({ ...file, status: 'done' }))]); } catch (error) { console.error('上传失败:', error); } };
- 修改Dragger组件的
onChange,只处理文件列表展示:
const handleChange = ({ fileList }) => { setFileList(fileList.filter(file => file.status !== "error")); };
<Dragger listType="picture-card" fileList={fileList} beforeUpload={beforeUpload} onPreview={handlePreview} onChange={handleChange} onRemove={handleOnRemove} multiple={true} > <AiOutlineUpload style={{ fontSize: 30 }} /> <div className="uploadText"> <p>拖拽到此处或点击选择文件</p> </div> </Dragger> {/* 添加手动上传按钮 */} <button onClick={handleManualUpload} style={{ marginTop: 16 }}> 开始上传 </button>
方案2:在原onChange中通过文件状态过滤,只处理新添加的文件
如果不想大幅改动原有逻辑,可以通过文件状态筛选,只处理刚添加的文件:
const handleChange = ({ fileList }) => { setFileList(fileList.filter(file => file.status !== "error")); // 只筛选状态为ready的新文件,避免重复处理 const newFiles = fileList.filter(file => file.status === 'ready' && !fileUploaded.find(x => x.name === file.name)); if (newFiles.length === 0) return; const handleUpload = async () => { try { for await (const file of newFiles) { const typeMedia = file.type.split('/')[0]; const nameOnCloud = typeMedia === "video" ? `videos/${file.name + v4()}` : `images/${file.name + v4()}`; const storageRef = ref(storage, nameOnCloud); await uploadBytes(storageRef, file.originFileObj); try { const link = await getDownloadURL(storageRef); setFileUploaded(prev => [...prev, { name: file.name, link: link, nameOnCloud: nameOnCloud, type: typeMedia }]); } catch (error) { console.error('获取下载链接失败:', error); } } } catch (error) { console.error('上传失败:', error); } }; handleUpload(); };
关键说明
- 方案1更推荐,完全掌控上传流程,避免组件默认的多次触发问题,也更符合用户操作习惯。
- 方案2是在原有逻辑上的修改,通过状态过滤减少重复上传,但仍可能存在组件多次触发带来的潜在问题。
内容的提问来源于stack exchange,提问作者Đạt Phạm
相关产品推荐
相关产品推荐

