NgRx 效果,ones 失败,不接受新动作

NgRx effect, ones failure occurs, does not accept new actions

@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
  });
})

但是我在这里迷路了。我不是反应式编程方面的专家,但除了这种情况外,一切都按预期进行。有谁知道为什么会发生这种情况?

您必须在每个内部可观察对象上添加 catchError,例如

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

有关详细信息,请参阅 NgRx 文档中的 handling errors 部分。

效果尊重成功完成和错误。如果出现错误,ngrx 将重新订阅,如果成功完成,则不会。

例如 catchError 可能会导致这种情况,因为它不监听其父流。如果您想在出现错误时启用流,您需要在 catchError.

之后立即使用 repeat 运算符
    catchError(error => {
      return of({
        type: UserActions.LOGIN_FAILURE,
        payload: error
      });
    }),
    repeat(), // <- now effect is stable.