【问题标题】:*ngFor using a function, returns a loop*ngFor 使用函数,返回一个循环
【发布时间】:2019-09-08 08:43:26
【问题描述】:

当我在 angular 中使用 *ngFor 和返回数据的函数时,该函数会被多次调用,有时甚至会导致循环:

app.component.ts

export class AppComponent {

 getArray(): string[] {

   //here i know when this function is called
   console.log('getArray called')

   return ['number one', 'number two']
 }

}

app.component.html

<h1 *ngFor="let item of getArray()">
 {{ item }}
</h1>

我的控制台:

然后我得到函数 getArray() 被多次调用,我不知道为什么。

【问题讨论】:

  • 在我的 app.component.html 中,第一行。

标签: angular typescript ngfor templatebinding


【解决方案1】:

更新

您会看到它被称为乘法时间,因为 Angular 在每个更改检测周期都会评估您在模板中使用的所有表达式。变更检测周期从ApplicationRef.tick 方法开始。

当应用程序启动它calls 时,立即使用tick 方法,然后它由ngZone.onMicrotaskEmpty 订阅管理。

此外,每个 tick 方法都会对开发模式执行额外的检查 checkNoChanges

所以你得到了

App starts
   loadComponent
      tick
        checkChanges
              evaluate getArray()
        checkNoChanges
              evaluate getArray()
  ngZone.onMicrotaskEmpty
      subscribe(all promised have been executed)
         tick
           checkChanges
              evaluate getArray()
           checkNoChanges
              evaluate getArray()

      ...some time later
      subscribe(you click somewhere)
         tick
           checkChanges
              evaluate getArray()
           checkNoChanges
              evaluate getArray()
      subscribe(you make a http request)
         tick
           checkChanges
              evaluate getArray()
           checkNoChanges
              evaluate getArray()

上一个答案

您应该避免在 Angular 模板中使用执行复杂计算或执行副作用或在每次更改检测运行时返回新值的表达式。

特别是在你的代码中

<h1 *ngFor="let item of getArray()">

每次模板检查都会返回一个新数组。并且 ngForOf 指令检测到您更改了数组并尝试重新渲染它(如果您的项目是一个对象)。

最好在代码中定义一次该数组。

arr = ['number one', 'number two']

<h1 *ngFor="let item of arr">

另一种适用于 ngForOf 指令的方法是使用 trackBy,但最好在 item 中有一些唯一的键。

另见

【讨论】:

  • 这解释了循环。我将改变我的代码策略。
  • 这个arr应该在哪里创建?
【解决方案2】:

@Yurzui 的回答实际上并不完全正确。这是一个例子:https://stackblitz.com/edit/angular-uqahdx

由于 Angular lifecycle hooks 的工作方式,它被多次调用。这是所有生命周期钩子都安装好后页面加载的控制台日志:

ngOnInit
ngDoCheck                       <!-- Detect and act upon changes that Angular can't or won't detect on its own.
ngAfterContentInit
ngAfterContentChecked           <!-- This is where the *ngFor ng-template is injected and getArray() is evaluated.
!>   getArray called               
ngAfterViewInit
ngAfterViewChecked              <!-- Angular ensures that the data hasn't changed between when the view "compilation" started and ended.
!>   getArray called               
ngDoCheck                       <!-- Angular then does an immediate pass over data bound elements 
ngAfterContentChecked           <!-- Angular has to call getArray yet again because the array reference in memory has changed as we are returning a new array. (like what @Yurzui said)
!>   getArray called               
ngAfterViewChecked              <!-- Angular runs the checking process again. This is where people get that "ExpressionChangedAfterItHasBeenCheckedError" error.
!>   getArray called            

如您所见,这些日志与您对getArray() 的 4 次调用的屏幕截图一致。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 2018-12-20
    • 2016-08-27
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    相关资源
    最近更新 更多