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

React中如何通过event.target.result获取多输入按钮的文件数据

上传多个文件的两种实现方案

方案一:并行独立上传每个文件(复用现有函数)

你的现有createUploadFileChannel已经支持单个文件上传,最直接的方式是对三个文件分别调用该函数,在Saga中并行处理三个上传任务。每个文件会通过独立的FileReader获取event.target.result,互不干扰。

步骤1:在Saga中发起多文件上传任务

import { call, put, take, all } from 'redux-saga/effects';
import { createUploadFileChannel, END } from './your-file-upload-channel';

function* uploadAllFilesSaga(url, files, opt) {
  // 为每个文件创建独立的上传channel
  const imageChannel = yield call(createUploadFileChannel, url, files.imageFile, { ...opt, AttachmentType: 2 });
  const letterChannel = yield call(createUploadFileChannel, url, files.letterFile, { ...opt, AttachmentType: 3 });
  const cvChannel = yield call(createUploadFileChannel, url, files.cvFile, { ...opt, AttachmentType: 4 });

  try {
    // 并行监听三个channel的上传状态与结果
    yield all([
      handleUploadChannel(imageChannel, 'image'),
      handleUploadChannel(letterChannel, 'letter'),
      handleUploadChannel(cvChannel, 'cv'),
    ]);
    yield put({ type: 'UPLOAD_ALL_SUCCESS' });
  } catch (err) {
    yield put({ type: 'UPLOAD_ALL_FAILED', payload: err });
  }
}

// 封装单个channel的通用处理逻辑
function* handleUploadChannel(channel, fileType) {
  while (true) {
    const action = yield take(channel);
    if (action.err) {
      throw new Error(`Upload ${fileType} failed: ${action.err.message}`);
    } else if (action.success) {
      console.log(`${fileType} upload success:`, action.data);
      return action.data;
    } else if (action.progress) {
      yield put({ type: `UPLOAD_${fileType.toUpperCase()}_PROGRESS`, payload: action.progress });
    }
  }
}

调用方式

// 从React Hook Form获取三个文件
const files = {
  imageFile: formValues.inputImage[0],
  letterFile: formValues.inputLetter[0],
  cvFile: formValues.inputCV[0],
};

// 在组件中触发Saga动作
dispatch({ type: 'UPLOAD_ALL_FILES', payload: { url: '/your-upload-endpoint', files, opt: {} } });

方案二:一次性打包上传三个文件(修改现有函数)

如果后端支持批量接收附件,可以修改createUploadFileChannel,等待三个文件全部读取完成后,组装包含所有文件数据的请求体发送。

修改后的多文件上传Channel函数

import { eventChannel, END } from 'redux-saga';
import store from './your-store'; // 你的Redux Store实例

export const createMultiUploadFileChannel = (url, files, opt) => {
  return eventChannel((emitter) => {
    const xhr = new XMLHttpRequest();
    
    // 为每个文件创建FileReader,收集读取Promise
    const fileReadTasks = Object.entries(files).map(([fileKey, file]) => {
      return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onloadend = (e) => {
          // 每个文件的event.target.result在这里获取
          resolve({
            AttachmentType: fileKey === 'imageFile' ? 2 : fileKey === 'letterFile' ? 3 : 4,
            Title: file.name,
            FileType: file.type,
            data: e.target.result,
          });
        };
        reader.readAsDataURL(file);
      });
    });

    const onProgress = (e) => {
      if (e.lengthComputable) {
        const progress = e.loaded / e.total;
        emitter({ progress });
      }
    };

    const onFailure = () => {
      emitter({ err: new Error('Upload failed') });
      emitter(END);
    };

    xhr.upload.addEventListener('progress', onProgress);
    xhr.upload.addEventListener('error', onFailure);
    xhr.upload.addEventListener('abort', onFailure);

    xhr.onreadystatechange = () => {
      const { readyState, status } = xhr;
      if (readyState === 4) {
        if (status === 200) {
          const resp = xhr.responseText;
          console.log('Multi upload response:', resp);
          emitter({ success: true, data: resp });
          emitter(END);
        } else {
          onFailure();
        }
      }
    };

    // 等待所有文件读取完成后发送请求
    Promise.all(fileReadTasks).then((attachments) => {
      const body = {
        ...opt,
        OpenWorkAttachments: attachments,
      };

      xhr.open('POST', url, true);
      xhr.setRequestHeader('Content-Type', 'application/json');
      xhr.setRequestHeader(
        'Authorization',
        `Bearer ${store.getState().client.user.data[0].access_token}`
      );

      xhr.send(JSON.stringify(body));
    }).catch(onFailure);

    return () => {
      xhr.upload.removeEventListener('progress', onProgress);
      xhr.upload.removeEventListener('error', onFailure);
      xhr.upload.removeEventListener('abort', onFailure);
      xhr.onreadystatechange = null;
      xhr.abort();
    };
  }, buffers.sliding(2));
};

在Saga中使用修改后的函数

function* uploadMultiFilesSaga(url, files, opt) {
  const multiChannel = yield call(createMultiUploadFileChannel, url, files, opt);

  try {
    while (true) {
      const action = yield take(multiChannel);
      if (action.err) {
        throw action.err;
      } else if (action.success) {
        console.log('All files uploaded:', action.data);
        yield put({ type: 'MULTI_UPLOAD_SUCCESS', payload: action.data });
        return;
      } else if (action.progress) {
        yield put({ type: 'MULTI_UPLOAD_PROGRESS', payload: action.progress });
      }
    }
  } catch (err) {
    yield put({ type: 'MULTI_UPLOAD_FAILED', payload: err.message });
  }
}

核心说明

  • 两种方案都通过每个文件对应独立的FileReader来获取event.target.result,确保文件数据不会混淆。
  • 方案一适合后端仅支持单个文件上传的场景,方案二适合后端支持批量上传的场景,可根据接口能力选择。

内容的提问来源于stack exchange,提问作者Lucas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 22:24:13