如何在RXJS retryWhen中触发/合并Observable并分发动作
在retryWhen中分发重试通知动作的最佳方案
嘿,这个场景我太熟悉了——在redux-observable里用retryWhen处理API重试时,要给用户反馈重试状态对吧?其实核心就是利用retryWhen的回调可以返回一个包含动作的Observable,毕竟epic就是靠返回Observable来dispatch动作的嘛。
你之前尝试用concat/merge没成功,大概率是没在错误流的每个值上做处理。我们可以用concatMap来逐个处理每个错误,先分发重试通知,再延迟触发重试,这样逻辑就顺了。
修改后的完整代码
export const saveArticle1 = (action$, state$) => action$.pipe( ofType(AUTO_SAVE_ARTICLE_READY), withLatestFrom(state$, (a, b) => b), switchMap(({ article, }) => { const payload = getArticlePayload(article); return ajax.patch(`/api/article/${article.id}`, payload, { 'Content-Type': 'application/json' }).pipe( flatMap(({ response }) => of({ type: ARTICLE_AUTO_SAVED, value: response, })), retryWhen(errors => errors.pipe( concatMap((error, retryCount) => { // 1. 先分发重试通知的Redux动作 const retryAction = { type: ARTICLE_SAVE_RETRYING, payload: `正在进行第${retryCount + 1}次重试(最多60次)` }; // 2. 先发送动作,再延迟1秒后触发下一次重试 return concat(of(retryAction), delay(1000)); }), take(60), // 限制最多重试60次 )), catchError((ex) => { articleSaveFailureAlert(); return showErrorNotification('Api Error. Unable to save this article.')(ex); }), ); }), );
关键逻辑说明
concatMap:遍历错误流的每个错误,把每个错误转换成一个包含「重试动作」+「延迟」的组合流。concat会保证先发送重试动作,再等待延迟,避免动作和重试触发顺序混乱。- 如果你的通知不是Redux动作,而是直接调用弹窗函数(比如
showRetryNotification),可以简化成这样:concatMap((error, retryCount) => { showRetryNotification(`第${retryCount+1}次重试中...`); return delay(1000); }) take(60):当重试次数达到60次后,retryWhen会停止重试,并把错误传递到后续的catchError中,触发最终的失败提示,这部分逻辑和你原来的代码一致,不用改动。
这样每次API请求失败触发重试时,都会先给用户发送重试通知,完美解决你的需求~
内容的提问来源于stack exchange,提问作者Tom Marulak
相关产品推荐
相关产品推荐

