@ ngrx / store pre-load guard catch错误

时间:2018-02-12 15:08:33

标签: angular rxjs ngrx ngrx-effects ngrx-store-4.0

我正在使用@ngrx / store处理Angular防护,以检查状态是否已经加载,并且我遇到了canActivate方法在我使用过滤器时永远不会返回的问题。

以下是GetCompanies操作的示例效果:

return this.companiesService.getCompanies()
  .pipe(
    map(companies => new companiesActions.GetCompaniesSuccess(companies)),
    catchError(error => Observable.of(new companiesActions.GetCompaniesFail(error)))
  )

如果出现错误,我将调度GetCompaniesFail操作并将用户重定向到/login页面。那很好,有趣的部分是守卫。

@Injectable()
export class CompaniesGuard implements CanActivate {
  constructor(
    private store: Store<AppState>,
    private router: Router
  ) {}

  canActivate(): Observable<boolean> {
    return this.checkStore()
      .pipe(
        switchMap(() => Observable.of(true)),
        catchError(() => Observable.of(false))
      );
  }

  checkStore(): Observable<boolean> {
    return this.store.select(getCompaniesLoaded)
      .pipe(
        tap(loaded => {
          if (!loaded) {
            this.store.dispatch(new companiesActions.GetCompanies());
          }
        }),
        filter(loaded => loaded),
        take(1)
      );
  }
}

如果出现错误并且加载不是false,则canActivate不会返回任何内容,因为checkStore什么都不做。

如果我将filter更改为map它可以正常工作,但即使数据成功加载,它也只需要false的第一个值。

我错过了什么?我该如何处理HTTP错误?有没有办法等待某个状态或在checkStore内抛出错误?

提前感谢!

1 个答案:

答案 0 :(得分:0)

如果你将职责分开一点,这似乎更容易处理。

您应该运行checkStore,而不是直接依赖它的结果。相反,让商店告知您成功或失败并返回结果。

请注意,ngrx和redux鼓励 单向数据流 来简化应用逻辑。

商店属性getCompaniesLoadedStatus初始化为初始,并在companiesActions.GetCompaniesSuccess内设置为成功失败companiesActions.GetCompaniesFail

重试在服务中处理(更接近获取)。

canActivate(): Observable<boolean> {
  this.checkStore();
  return this.store.select(getCompaniesLoadedStatus).pipe(
    filter(status => status !== 'initial'),
    map(status => status === 'success' ? true : false )
  );
}

checkStore(): void {
  this.store.select(getCompaniesLoadedStatus).pipe(
    take(1)  // so that unsubscribe is not needed
  ).subscribe(status =>
    if (status === 'initial') { 
      this.store.dispatch(new companiesActions.GetCompanies());
    }
  );
}