Эффект NgRx, происходит сбой, новые действия не принимаются - PullRequest
1 голос
/ 27 мая 2020
@Injectable()
export class UserEffects {
  constructor(
    private store$: Store<fromRoot.State>,
    private actions$: Actions,
    private router: Router,
    private chatService: ChatService,
    private authService: AuthService,
    private db: AngularFireAuth,
    private http: HttpClient
  ) { }

  @Effect()
  login$: Observable<Action> = this.actions$.pipe(
    ofType(UserActions.LOGIN),
    switchMap((action: UserActions.LoginAction) =>
      from(this.db.auth.signInWithEmailAndPassword(action.payload.email, action.payload.password)),
    ),
    // switchMapTo(from(this.db.auth.currentUser.getIdToken())),
    switchMapTo(from(this.db.authState.pipe(
      take(1),
      switchMap((user)=>{
        if (user)
          return from(user.getIdToken());
        else
          return of(null);
      })
    ))),
    switchMap(token => this.http.post(environment.apiUrl + '/api/login', { token: token })),
    tap((response: any) => {
      if (response.valid === 'true') {

        localStorage.setItem('token', response.token);

        this.router.navigate(['dash']);

      }
    }),
    map(response => new UserActions.LoginSuccessAction({ response })),
    catchError(error => {
      return of({
        type: UserActions.LOGIN_FAILURE,
        payload: error
      });
    })
  );

  @Effect({ dispatch: false })
  loginSuccess$: Observable<Action> = this.actions$.pipe(
    ofType(UserActions.LOGIN_SUCCESS),
    tap((action: UserActions.LoginSuccessAction) => {
      console.log("LOGIN_SUCCESS");
      console.log(action);
    }));

    @Effect({ dispatch: false })
    loginFailure$: Observable<Action> = this.actions$.pipe(
      ofType(UserActions.LOGIN_FAILURE),
      tap((action: UserActions.LoginFailureAction)=>{
        console.log("LOGIN_FAILURE");
        console.log(action.payload.code);
      }));
}

Пример использования: вы находитесь на странице входа. Вы вводите свое имя пользователя и пароль для вызова LoginAction. Если все пойдет хорошо, следует вызвать LoginSuccessAction. В противном случае следует вызвать LoginFailureAction.

Все работает, кроме одного случая:
После однократного вызова LoginFailureAction ни LoginSuccessAction, ни LoginFailureAction не вызываются снова. Я не понимаю, почему это происходит. Я думаю, это может иметь какое-то отношение к строке:

catchError(error => {
  return of({
    type: UserActions.LOGIN_FAILURE,
    payload: error
  });
})

, но здесь я потерялся. Я не специалист по реактивному программированию, но все работает так, как должно, за исключением этого случая. Кто-нибудь знает, почему это происходит?

Ответы [ 2 ]

1 голос
/ 27 мая 2020

Эффекты касаются успешного завершения и ошибок. В случае ошибки ngrx повторно подпишется, в случае успешного завершения не будет.

Например, catchError может вызвать этот случай, потому что он не слушает свой родительский поток. Если вы хотите включить поток в случае ошибки, вам необходимо использовать оператор repeat сразу после catchError.

    catchError(error => {
      return of({
        type: UserActions.LOGIN_FAILURE,
        payload: error
      });
    }),
    repeat(), // <- now effect is stable.
0 голосов
/ 27 мая 2020

Вам нужно будет добавить catchError для каждого внутреннего наблюдаемого, например

switchMap(token => this.http.post(environment.apiUrl + '/api/login', { token: token }).pipe(catchError(...)),

См. Раздел обработка ошибок в документации NgRx для получения дополнительной информации.

...