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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:15:03