Redux Saga actionChannel文件上传动作串行执行失效问题排查
问题分析与修正方案
核心问题点
fileUploadSaga写法错误:直接返回包含yield的数组,未正确启动监听saga;rootSaga中错误地展开generator函数而非调用后的迭代器。- Worker Saga 未接收Action参数:
watchRequests中调用worker saga时,未传递当前action,导致API调用缺少action.payload。 - XSRF Token 未传递:未实现将前一次请求返回的token注入下一次请求的逻辑。
修正后的完整代码
1. 修正Saga核心逻辑
import { take, actionChannel, call, put } from 'redux-saga/effects'; import { AnyAction } from 'redux'; import { ServicesType } from '../services/types'; import { uploadLossOfAccountMaleSuccess, uploadLossOfAccountFemaleSuccess, fetchDataFailure, UploadExistingAccountMaleSuccess, UploadExistingAccountFemaleSuccess } from './actions'; import { UPLOAD_ACCOUNT_LOSS_REQUEST_MALE, UPLOAD_ACCOUNT_LOSS_REQUEST_FEMALE, UPLOAD_ACCOUNT_EXIST_REQUEST_MALE, UPLOAD_ACCOUNT_EXIST_REQUEST_FEMALE } from './actionTypes'; type Services = Pick<ServicesType, 'FileUpload'>; // 存储最新的XSRF Token let latestXSRFToken: string | undefined; function uploadLossOfAccount(services: Services, gender: string) { return function* (action: AnyAction) { try { // 注入最新的XSRF Token到请求头 const config = { headers: latestXSRFToken ? { 'X-XSRF-TOKEN': latestXSRFToken } : {} }; const data = yield call(services.FileUpload.postData, action.payload, config); // 更新XSRF Token if (data.xsrfToken) { latestXSRFToken = data.xsrfToken; } gender === "male" ? yield put(uploadLossOfAccountMaleSuccess(data)) : yield put(uploadLossOfAccountFemaleSuccess(data)); } catch (error) { yield put(fetchDataFailure((error as Error).message)); } }; } function UploadExistingAccount(services: Services, gender: string) { return function* (action: AnyAction) { try { // 注入最新的XSRF Token到请求头 const config = { headers: latestXSRFToken ? { 'X-XSRF-TOKEN': latestXSRFToken } : {} }; const data = yield call(services.FileUpload.postData, action.payload, config); // 更新XSRF Token if (data.xsrfToken) { latestXSRFToken = data.xsrfToken; } gender === "male" ? yield put(UploadExistingAccountMaleSuccess(data)) : yield put(UploadExistingAccountFemaleSuccess(data)); } catch (error) { console.error('上传失败:', error); } }; } function* watchRequests(services: Services) { const requestChannel = yield actionChannel([ UPLOAD_ACCOUNT_LOSS_REQUEST_MALE, UPLOAD_ACCOUNT_LOSS_REQUEST_FEMALE, UPLOAD_ACCOUNT_EXIST_REQUEST_MALE, UPLOAD_ACCOUNT_EXIST_REQUEST_FEMALE ]); while (true) { const action = yield take(requestChannel); // 关键:传递action给worker saga switch (action.type) { case UPLOAD_ACCOUNT_LOSS_REQUEST_MALE: yield call(uploadLossOfAccount(services, "male"), action); break; case UPLOAD_ACCOUNT_LOSS_REQUEST_FEMALE: yield call(uploadLossOfAccount(services, "female"), action); break; case UPLOAD_ACCOUNT_EXIST_REQUEST_MALE: yield call(UploadExistingAccount(services, "male"), action); break; case UPLOAD_ACCOUNT_EXIST_REQUEST_FEMALE: yield call(UploadExistingAccount(services, "female"), action); break; } } } export default function* fileUploadSaga(services: Services) { // 正确启动监听saga yield call(watchRequests, services); }
2. 修正RootSaga
import { all } from 'redux-saga/effects'; import fileUploadSaga from './fileUploadSaga'; // 导入其他sagas // import remainingSagas from './remainingSagas'; // 假设services在rootSaga中注入 import services from '../services'; export default function* rootSaga() { yield all([ fileUploadSaga(services), // ...remainingSagas // 其他saga直接放入数组 ]); }
关键修正说明
- 修复Saga启动逻辑:
fileUploadSaga不再返回数组,直接调用watchRequests;rootSaga中正确传入services并启动saga,而非展开generator函数。 - 传递Action参数:调用worker saga时,先执行
uploadLossOfAccount(services, "male")获取generator,再传入action,确保worker能拿到action.payload。 - XSRF Token 传递:新增全局变量存储最新token,每次请求前注入请求头,请求成功后更新token,保证串行请求的token连贯性。
- 语法错误修复:修复了actions导入时的逗号缺失、
fileUploadSaga中的括号错误。
内容的提问来源于stack exchange,提问作者MMR
相关产品推荐
相关产品推荐

