Ngrx导致挂起问题,直到订阅store.dispatch时页面被重新加载

问题描述

我是Ngrx商店的新手,但是我有一个可行的实现方式。

我注意到我正在建立的登录屏幕中有一个奇怪的行为。我想以特定方式处理GetUserFailures,因此我订阅ScannedActionsSubject并按操作类型进行过滤。

export class LoginComponent implements OnInit {

  constructor(
    private userService: UserService,private store: Store<AppState>,private actions$: ScannedActionsSubject,) {
    ...
  }

  ngOnInit() {
    this.actions$
      .pipe(filter((action: any) => action.type === '[User] Get User Failure'))
      .subscribe((action: any) => {
        const error = action.payload.error.response;
        this.handleError(error);
        if (error && error.includes('not found')) {
          this.snackBar.open('Sorry,we have no record of that email address.','OK');
        } else if (error && error.includes('Invalid credentials')) {
          this.snackBar.open('The password you entered is incorrect.','OK');
        }
        if (this.loading) this.loading = false;
      });
  }

  async login(event: any) {
    if (event) event.preventDefault();

    // if the user is logging in for the first time,show update password form
    if (this.validateForm(this.loginForm)) {
      this.loading = true;
      const email = this.loginForm.controls.email.value;
      email && this.store.dispatch(new GetUserByEmail(email));
      this.store.select(selectUserByEmail)
        .pipe(filter(result => result.user !== (null || undefined)))
        .subscribe(
          async (result) => {
            this.user = result.user;
            if (this.user && this.user.status === 'Pending') {
              const email = this.loginForm.controls.email.value;
              const password = this.loginForm.controls.password.value;
              email && password && this.userService.validatePasswordHash(email,password).subscribe(
                (result) => {
                  if (result) {
                    this.loading = false;
                    this.loginStepper.selectedindex = 2;
                    this.hidePassword = true;
                  }
                },(error) => {
                  this.handleError(error);
                  if (error.error && error.error.response.includes('Invalid credentials')) {
                    this.snackBar.open('The password you entered is incorrect.','OK');
                    this.loading = false;
                    return;
                  }
                },);
            } else if (this.user && this.user.status === 'Active') {
              localStorage.setItem('USER_AUTHD','true');
              await this.router.navigateByUrl('/home');
              this.snackBar.open(`Welcome back,${this.user.recipientFullName.split(' ')[0]}!`,'OK',{ duration: 4000 });
            } else {
              console.log('neither active nor pending!',this.user);
            }
            this.loading = false;
            return;
          },(error) => {
            console.log('Error getting user by email',error);
            return;
          },() => {  // complete
            if (this.loading) this.loading = false;
          },);
  }
}

当发生错误时,错误会得到正确处理,但是当我尝试再次启动登录过程时,store.select段会无限期挂起,并且我似乎无法找出原因。就可读性而言,它绝对不是最好的实现,但是我为工作功能提供了所有这些。

重申一下,在第一次登录尝试失败后,每次在登录流“挂起”之后,特别是this.store.select(selectUserByEmail)内挂起之后,每次尝试登录,但是要跟踪挂起的原因很困难,因为我只能看到作为对GetUserByEmail的网络请求,该请求有效。

我希望能够“重新加载”系统以进行更多登录尝试。

GetUserByEmail效果

@Injectable()
export class UserEffects {

  @Effect()
  getUserByEmail$: Observable<any> = this.actions$.pipe(
    ofType<GetUserByEmail>(UserActionsEnum.GetUserByEmail),switchMap((action) => this.userService.getUserByEmail(action.payload)),map((response) => new GetUserSuccess(response)),catchError((error) => of(new GetUserFailure(error))),);
}

减速器:

case UserActionsEnum.GetUserByEmail:
  return {
    ...state,user: action.payload?.data,loading: false,};

解决方法

最初的问题是由于错误,这种影响将被取消。因此,您可以做的是将catchError的{​​{1}}的内部可观察区域移动:

switchMap