如何让Ngrx Effect实现take(1)效果且登录登出后可自动重置
解决方案1:take(1) + repeatWhen 组合(最贴合需求)
你可以在原有take(1)的基础上,新增repeatWhen监听登出动作,登出后自动重置Effect的订阅状态,既保证单账号周期内仅触发一次请求,又能在切换账号后正常重新拉取数据:
// 假设你的登出成功Action为A.logoutSuccess,可替换为项目实际的登出Action getBooks$ = createEffect(() => this.actions.pipe( ofType(A.getBooks), take(1), switchMap(() => this.bookService.getBooks().pipe( map((books) => A.getBooksOk({ books })), catchError(() => EMPTY), ), ), // 监听到登出动作时重订阅Effect,重置take(1)的计数 repeatWhen(complete$ => complete$.pipe( skipUntil(this.actions.pipe(ofType(A.logoutSuccess))) )) ), );
原理说明:
take(1)保证单次订阅周期内,getBooksaction仅触发一次请求,同个账号登录期间无论多少次跳转个人主页都不会重复发起请求repeatWhen会在Effect流完成后等待登出信号,登出时自动重新订阅整个Effect流,相当于重置了take(1)的状态,新账号登录后触发getBooks时会正常发起请求- 该方案完全避免了请求竞态问题,也不需要在store中维护额外的
booksLoaded类标识,代码改动量极小,且可以快速复用给其他同逻辑的Effect。
解决方案2:exhaustMap + takeUntil 组合(逻辑更简洁)
如果你不想处理重订阅逻辑,也可以用exhaustMap自带的「忽略后续同类型action直到当前流完成」的特性,搭配登出信号终止订阅,也能实现相同效果:
getBooks$ = createEffect(() => this.actions.pipe( ofType(A.getBooks), // 登出时终止当前订阅,重置exhaustMap的状态 takeUntil(this.actions.pipe(ofType(A.logoutSuccess))), // 只要第一个请求还未完成/已完成,就忽略所有后续的getBooks action exhaustMap(() => this.bookService.getBooks().pipe( map((books) => A.getBooksOk({ books })), catchError(() => EMPTY), ), ), ), );
内容的提问来源于stack exchange,提问作者InsertUsernameHere
相关产品推荐
相关产品推荐

