Angular自定义错误处理程序和NGRX引起无限循环

发布于 2025-01-19 14:00:48 字数 1261 浏览 2 评论 0原文

在 Angular 应用程序中,我实现了一个自定义错误处理程序,它显示警报(Angular Material 小吃栏)并调度 ngrx 操作来隐藏加载微调器。

这是一个错误处理程序:

export class ErrorHandlerService extends ErrorHandler {
  constructor(private snackbar: SnackbarService, private store: Store<AppState>) {
    super();
  }

  override handleError(error: any): void {
    super.handleError(error);
    const msg =
      error.rejection?.message ?? error.error?.message ?? error.message;
    this.snackbar.openSnackBar(msg, true);
    this.store.dispatch(loadingZero());
  }
}

reducer 将侦听 LOADING_ZERO 操作并将计数器设置为 0(如果计数器大于零,则显示加载微调器;如果计数器等于零,则隐藏)。

根组件订阅选择器并分别显示/隐藏微调器。我正在使用 ngx-spinner。

export class AppComponent implements OnInit, OnDestroy {
  isLoading$ = this.store.select(isLoadingSelector);
  _destroying$ = new Subject<boolean>();

  constructor(
    private spinner: NgxSpinnerService,
    // ...
  ) {}

  ngOnInit() {
    this.isLoading$
      .pipe(takeUntil(this._destroying$))
      .subscribe((value) =>
        value ? this.spinner.show() : this.spinner.hide(),
      );
    // ...
  }
  
  // ...
}

问题是这样的:渲染模板时出错会导致无限循环。其他错误(如失败的 HTTP 请求)则不会。如果我不在错误处理程序中分派 ngrx 操作,则错误也不会循环。

我猜这与变更检测有关,但仍然无法弄清楚。

In an Angular app, I implemented a custom error handler which shows an alert (Angular Material snackbar) and dispatches a ngrx action to hide a loading spinner.

Here is an error handler:

export class ErrorHandlerService extends ErrorHandler {
  constructor(private snackbar: SnackbarService, private store: Store<AppState>) {
    super();
  }

  override handleError(error: any): void {
    super.handleError(error);
    const msg =
      error.rejection?.message ?? error.error?.message ?? error.message;
    this.snackbar.openSnackBar(msg, true);
    this.store.dispatch(loadingZero());
  }
}

The reducer would listen to LOADING_ZERO action and set the counter to 0 (loading spinner is shown if the counter is more than zero, and hidden if it equals zero).

The root component subscribes to the selector and shows/hides the spinner respectively. I'm using ngx-spinner.

export class AppComponent implements OnInit, OnDestroy {
  isLoading$ = this.store.select(isLoadingSelector);
  _destroying$ = new Subject<boolean>();

  constructor(
    private spinner: NgxSpinnerService,
    // ...
  ) {}

  ngOnInit() {
    this.isLoading$
      .pipe(takeUntil(this._destroying$))
      .subscribe((value) =>
        value ? this.spinner.show() : this.spinner.hide(),
      );
    // ...
  }
  
  // ...
}

Here is the problem: an error in rendering a template leads to infinite loop. Other errors (like a failed HTTP request) do not. If I do not dispatch a ngrx action in the error handler, the error does not get looped as well.

I guess it has something to do with change detection, but still unable to figure it out.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜灵血窟げ 2025-01-26 14:00:48

我发现保留请求计数器很容易出错(正如您在此处看到的那样)。
更好的解决方案是存储每个实体的请求状态,并将所有加载状态合并为一个。这可以进一步扩展(如果需要),并根据待处理的请求显示不同的微调器。

话虽这么说,“渲染模板时的错误导致无限循环”让我认为计数器将为负(或者统计数据将关闭),因此将显示微调器。

解决方案是仅在错误是 HTTP 错误时分派该操作,或者您也可以实现一个 HTTP 拦截器来分派该操作。这样,只有失败的 HTTP 请求才会发送错误。

I find that keeping a request counter is error-prone (as you can see here).
A better solution would be to store the request state per entity, and combine all loading states into one. This can further be extended (if needed), and show different spinners based on which request is pending.

That being said, "an error in rendering a template leads to infinite loop" makes me think that the counter will be negative (or the stats will be off), and thus will show the spinner.

A solution would be to only dispatch the action if the error is a HTTP error, or you could also implement a HTTP Interceptor, which dispatches the action. This way, the error will only be dispatched for failing HTTP requests.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文