You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ant Design Dragger组件多文件上传:onChange多次触发致重复文件问题

解决Ant Design Dragger多文件上传时onChange多次触发导致重复上传的问题

问题原因

Ant Design的Upload组件(包括Dragger)开启multiple后,每添加一个文件就会触发一次onChange事件。你的代码在每次onChange中都会遍历处理所有未上传的文件,后续的onChange调用会重复处理之前已经上传过的文件,最终造成重复上传。

解决方案

方案1:用beforeUpload阻止自动上传,手动收集文件后一次性提交

这种方式完全由自己控制上传流程,更可控:

  1. 修改beforeUpload,返回false阻止组件自动上传,同时收集选中的文件:
const [pendingFiles, setPendingFiles] = useState([]);

const beforeUpload = (file) => {
  setPendingFiles(prev => [...prev, file]);
  return false;
};
  1. 新增手动上传逻辑,在合适时机(比如用户点击确认按钮)执行:
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);
  }
};
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 22:21:39