Search code examples
angularreduxrxjsngrxreactivex

@ngrx/effects API request handling


I had a case where my login form was stopping working after a single failure login attempt, for making request I've been using effect, and that's how it was looking before changes:

@Effect()
login$ = this.actions$.ofType<authActions.Login>(
  authActions.LOGIN,
).switchMap(
  ({ payload: data }) => this.client.login(data),
).map(
  ({ token }) => new authActions.LoginSuccess(token),
).catch(
  (error) => of(new authActions.LoginFailure(error)),
);

To be specific - when an user was trying to login after a failure attempt the Login action was dispatched correctly to the store, yet the effect was not launching.

I was desperately trying to fix that bug, then I've made a change that I thought was meaningless:

@Effect()
login$ = this.actions$.ofType<authActions.Login>(
  authActions.LOGIN,
).switchMap(
  ({ payload: data }) => this.client.login(data).map(
    ({ token }) => new authActions.LoginSuccess(token),
  ).catch(
    (error) => of(new authActions.LoginFailure(error)),
  ),
);

But fortunately that (IMO) meaningless change fixed everything. Suddenly the effect was successfully launching after a failure login attempt. Could somebody explain me what happen?


Solution

  • When an error is caught by the catch (or, in RxJS version 6, catchError) operator, the composed observable continues with a different observable.

    That means that when an error occurs, your effect continues with the of(new authActions.LoginFailure(error)) observable that's returned within the catch.

    Continuing with that observable will see the LoginFailure action dispatched, but after that, the observable completes. That means the effect completes and its subscribers are then automatically unsubscribed. So the effect stops dispatching further actions.

    This is discussed in more detail in Paul Lessing's article Handling Errors in NgRx Effects and there is a TSLint rule - rxjs-no-unsafe-catch - to detect this particular problem in my rxjs-tslint-rules package.