Angular *ngIf 多次调用,使用异步管道和订阅

时间:2021-03-11 19:45:09

标签: angular typescript rxjs observable

我当前的角度设置存在问题,我无法弄清楚到底是哪里出了问题。 在我开始解决问题之前,我会先描述一些上下文。

我有一个类 - data-service.ts,里面有一个方法“getData”。这是身体:

getData(): Observable<Data[]> {
let params = new HttpParams();
params = params.append('user_id', this.userId);
return this.http.get<Data[]>('api/data', {
  observe: 'body',
  responseType: 'json',
  params
}).pipe(
    map((response: any[]) => {
      return response.map((s) => ({
        id: s.id,
        userId: s.user_id,
        type: s.type_id,
        ...
      }));
    })
);}

我的要求是每次用户在 ngModal 中输入目标选项卡时获取这些数据并刷新视图。 当您单击该目标选项卡时,模态组件“modal-component.ts”会获取此数据。单击选项卡会触发一个事件,通过这段代码:

getData(evt) {
  this.data$ = this.dataSevice.getData();
}

我正在使用异步管道将此“data$” observable 传递给子组件:

<modal-component>
...
    <app-data-manager [data]="data$ | async"></app-data-manager>
...
</modal-component>

在“数据管理器”内部,我在 [data] 上使用 *ngFor,并且对于每个数据,我都渲染了一些 html。在那个 HTML 中,我使用 *ngIf 来确定应该呈现哪个模板,第一个还是第二个。

<div *ngIf="isTrue(dataEntry); then first else second"></div>

问题是: 为每个数据条目调用 isTrue 方法,这很好,但它会为整个数据集调用多次。就像数百次一样。我尝试使用承诺,使用 Take(1) 管道,在映射期间分配布尔值(ngIf 用来选择模板的那个),在订阅内分配数据并传递普通集合而不是使用异步管道。我不知道这是导致这种情况的原因 - 我很感激对那个人的每一个帮助。谢谢!

附加信息 当我在 *ngIf 中使用 dataEntry.isTrue 而不是 isTrue(dataEntry) 时 - 我仍然得到相同的结果。我还在带有控制台日志的子组件中添加了“OnChanges” - 第一次单击它会记录到控制台一次,第二次单击它会记录到控制台两次。出现两条相同的消息。

1 个答案:

答案 0 :(得分:4)

问题是您在角度表达式中使用了函数调用。不要这样做。

<块引用>

[T]isTrue() 函数在每次运行 Angular 变化检测时都会执行。这可能是很多次!

<块引用>

由于 Angular 无法预测 isTrue() 的返回值是否发生变化,所以每次变化检测运行时都需要执行该函数。

这意味着整个应用程序(包括 app-data-manager 组件外部)的任何更改检测都将导致 isTrue() 执行。

这篇文章对此进行了更多讨论:https://medium.com/showpad-engineering/why-you-should-never-use-function-calls-in-angular-template-expressions-e1a50f9c0496

一种解决方案是使用属性而不是函数。如果您想结束复杂的逻辑,请选择像这样制作自定义管道。

*ngIf="(dataEntry | isTruePipe); then first else second"></div>

相关问题