[英]redux-saga: retry catched actions after token refresh
我在redux-saga
頻道中分組了一組操作。 它們中的每個(或同時)可能由於令牌過期而失敗。 如何暫停以后的操作以防止下次失敗,在刷新令牌和取消暫停通道后重試已捕獲的操作。
function* watchRequests() {
// a set of simultaneous actions which utilize access token from store
const requestChannel = yield actionChannel('*_REQUEST')
while (true) {
try {
const { payload } = yield take(requestChannel)
yield fork(handleRequest, payload)
} catch (error) {
if (error === 'EXPIRED_ACCESS_TOKEN') {
const newToken = yield call(refreshToken)
yield call(setAccessToken, newToken)
} else {
throw error
}
} finally {
// after success token refresh
// 1. retry catched action
// 2. unsuspend rest actions from channel
}
}
}
在這里處理相同的概念,但是使用不同的配方。
以下是代碼的關鍵部分,但請注意,它仍在進行中。
關鍵是派生了“ api.refreshSession”,並且在此任務仍在運行時,每個REFRESH_SESSION操作都將加入已在運行的任務,而不是啟動一個新任務。
function* refreshSessionListener() {
let task;
while (true) {
const action = yield take(REFRESH_SESSION);
if (task === undefined || !task.isRunning()) {
task = yield fork(api.refreshSession);
}
// non-blocking join
yield fork(joinRefreshSessionTask, task, action);
}
}
function* joinRefreshSessionTask(task, action) {
const response = yield join(task);
if (response.status === 200) {
yield fork(action.onSuccess);
} else {
yield fork(action.onError, response);
}
}
export function* apiSaga(...args) {
const [fn, { type, payload, meta = {} }] = args;
try {
const data = yield call(fn, payload);
yield* okSaga(type, e);
} catch (e) {
if (e.tokenExpired) {
yield put({
type: REFRESH_SESSION,
onSuccess: apiSaga.bind(null, ...args),
onError: errorSaga.bind(null, type)
});
return;
} else {
yield* errorSaga(type, e);
}
}
}
runSaga(refreshSessionListener)
我在應用程序的其他部分使用上述內容:
import {apiSaga} from ...
function* listenToActions () {
yield takeEvery(POST_SOMETHING, apiSaga.bind(null, api.postSomething));
yield takeLatest(GET_SOMETHING, apiSaga.bind(null, api.getSomething));
}
runSaga(listenToActions);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.