Ngrx效果:有条件地在switchMap内返回动作而不是http响应

时间:2018-04-20 20:11:48

标签: angular rxjs angular5 ngrx ngrx-effects

我目前正在使用Angular 5应用程序,该应用程序将使用ngrx-store的一些缓存策略,允许用户查看项目并返回主列表而无需再次发出请求。

我使用效果来请求数据并使用reducer根据我的htp响应更新我的全局状态。如您所见,为了成功,会触发RequestPartnersSuccess操作,并且对于错误,会触发RequestPartnersFail。

该物业' internalAppDynamic.searchPartners.recoverLatest'从我的全局状态指示我是否应该从缓存中恢复我的列表,在这种情况下,效果应该返回一个方法,如果'声明并完成我的流程。

@Effect()
  loadPartners$ = this.actions$
    .ofType(SearchPartnersActions.REQUEST_PARTNERS)
    .withLatestFrom(this.store$, (action, state) => {
      action = Object.assign(action, {recoverLatest: state.internalAppDynamic.searchPartners.recoverLatest})
      return action
    })
    .pipe(switchMap((action: any) => {
      if (action.recoverLatest) {
        return new SearchPartnersActions.RequestPartnersRecoverCache()
      }
      return this.internalPartnersService.getPartners(action.payload).pipe(
        map(partners => new SearchPartnersActions.RequestPartnersSuccess(partners)),
        catchError(error => of(new SearchPartnersActions.RequestPartnersFail(error)))
      )
    }))

这是我服务中的getPartners()函数:

getPartners (body): Observable<any> {
    return this.http
    .post(this._baseUrl + 'internal-app/get-partners', body, this.httpOptions)
    .pipe(catchError((error: any) => this.errorHandler(error)))
  }

事情是我无法找到实现这一结果的方法。我是rxjs和Observables的新手,我认为switchMap运算符需要另一种返回,而不是我的SearchPartnersActions.RequestPartnersRecoverCache()类的新实例。

我能做些什么来达到理想的效果?有人能更好地向我解释一下Observables的预期效果吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

I was able to achieve the desired behavior by creating an auxiliary observable just to be able to pass my action inside the stream, like this:

  auxObservable () {
    return Observable.create((observer) => {
      observer.next()
    })
  }

  @Effect()
  loadPartners$ = this.actions$
    .ofType(SearchPartnersActions.REQUEST_PARTNERS)
    .withLatestFrom(this.store$, (action, state) => {
      action = Object.assign(action, {recoverLatest: state.internalAppDynamic.searchPartners.recoverLatest})
      return action
    })
    .pipe(switchMap((action: any) => {
      if (action.recoverLatest) {
        return this.auxObservable().pipe(
          map(res => new SearchPartnersActions.RequestPartnersRecoverCache())
        )
      }
      return this.internalPartnersService.getPartners(action.payload).pipe(
        map(partners => new SearchPartnersActions.RequestPartnersSuccess(partners)),
        catchError(error => of(new SearchPartnersActions.RequestPartnersFail(error)))
      )
    }))

If you need to pass your action object inside the stream to use it's type or payload for something else, you should pass it as a auxObservable parameter, like this:

  auxObservable (action) {
    return Observable.create((observer) => {
      observer.next(action)
    })
  }

  @Effect()
  loadPartners$ = this.actions$
    .ofType(SearchPartnersActions.REQUEST_PARTNERS)
    .withLatestFrom(this.store$, (action, state) => {
      action = Object.assign(action, {recoverLatest: state.internalAppDynamic.searchPartners.recoverLatest})
      return action
    })
    .pipe(switchMap((action: any) => {
      if (action.recoverLatest) {
        return this.auxObservable(action).pipe(
          map(res => new SearchPartnersActions.RequestPartnersRecoverCache())
        )
      }
      return this.internalPartnersService.getPartners(action.payload).pipe(
        map(partners => new SearchPartnersActions.RequestPartnersSuccess(partners)),
        catchError(error => of(new SearchPartnersActions.RequestPartnersFail(error)))
      )
    }))

I think someone might need this technique in the future, so I'm sharing my solution =)

If someone can think about a better way to intercept the default stream behavior if a condition is met and trigger a diferent reducer case, please share it with us!

Update:

As Alexander pointed out, the auxObservable is not necessary and it's possible to just return of(new SearchPartnersActions.RequestPartnersRecoverCache()), making sure you imported the 'of' operator from rxjs.

Thanks!