我正在使用
redux-saga
和 @reduxjs/toolkit
。我发出一些 Web 服务请求并将它们的响应保存到 redux 中,并且我遵循我在一些地方提到过的挂起/成功/失败模式。对于我的 Redux 传奇:
export default function* rootSaga() {
yield takeEvery(actionGetData.toString(), handleGetData);
}
用我的生成器功能:
function* handleGetData(action: any): Generator<any, any, any> {
yield put({ type: 'ACTION.GETDATA_PENDING', payload: action.payload });
try {
const response = yield call(apiRequest);
const responseData = response.data;
yield put({ type: 'ACTION.GETDATA_FULFILLED', payload: { name: action.payload, data: responseData } });
} catch (error: any) {
yield put({ type: 'ACTION.GETDATA_FAILED', payload: { name: action.payload, data: error.message } });
}
}
我将这个状态(待处理、成功、失败)保存到 redux 中,屏幕上有一个与这个状态对应的可视组件——加载动画,或者成功/失败通知等。
这一切都很好,但问题是,当这个
apiRequest
需要一段时间才能完成并且时,用户会过早地取消请求 - 例如,在 Web 服务请求返回响应之前关闭页面。这种情况下,当用户重新加载页面时,状态就卡在了“loading”状态,除了这一次,不会发出apiRequest
,所以没有办法以成功或失败的方式退出这个状态,所以向用户显示永无休止的加载动画,并且无需重试 Web 服务请求。
我该如何解决这个问题?有没有办法调用可以在函数退出之前执行的清理函数(例如,如果页面过早停止,则立即调用“失败”操作)?有没有办法“观察”这个“待处理”状态,并在卡住一定时间后触发重试?
为了解决这个问题,我最终在我的 root saga 开始时添加了对待处理和拒绝的 Web 服务请求的检查:
function* handlePendingRequestsSaga() {
yield put({ type: actionClearPendingDataRequests.toString() });
yield put({ type: actionRetryRejectedDataRequests.toString() });
}
export default function* rootSaga() {
yield handlePendingRequestsSaga();
yield takeEvery(actionGetData.toString(), handleGetResource);
}
在相应的减速器中,
actionClearPendingDataRequests
会接受标记为待处理的请求并将其移至拒绝状态,而 actionRetryRejectedDataRequests
则会重试之前标记为拒绝的请求。因为 handlePendingRequestsSaga
在初始化时触发(例如,当刷新或首次加载页面时),任何被中断的请求都将被标记为拒绝并自动重试,并且之前失败的任何请求也将被重试(一次)。如果这些再次失败且没有中断,则页面工作流程将按预期进行(向用户显示失败请求的错误消息等)。