*ngFor 使用一个函数,returns 一个循环
*ngFor using a function, returns a loop
当我在 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>
My console:
然后我多次调用 getArray() 函数,我不知道为什么。
更新
您看到它被称为乘法时间,因为 Angular 在每个更改检测周期中评估您在模板中使用的所有表达式。变更检测周期从 ApplicationRef.tick 方法开始。
应用程序启动时 calls that tick method immediately and then it's managed by 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 模板中使用表达式来执行复杂的计算或执行副作用或 return 每次更改检测时的新值 运行。
特别是在您的代码中
<h1 *ngFor="let item of getArray()">
您在每次模板检查时都return创建一个新数组。并且 ngForOf 指令检测到您更改了数组并尝试重新呈现它(如果您的项目是对象)。
最好在代码中定义一次该数组。
arr = ['number one', 'number two']
<h1 *ngFor="let item of arr">
另一种适用于 ngForOf 指令的方法是使用 trackBy,但最好在 item 中为此设置一些唯一键。
另见
@Yurzui 的回答其实并不完全正确。这是一个例子:https://stackblitz.com/edit/angular-uqahdx
由于 Angular lifecycle hooks 的工作方式,它被多次调用。这是设置所有生命周期挂钩后页面加载的 console.log:
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
如您所见,这些日志与您的屏幕截图一致,其中有 4 次调用 getArray()
。
如果你想在你的“项目”中进行操作,你可以使用angular管道
当我在 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>
My console:
然后我多次调用 getArray() 函数,我不知道为什么。
更新
您看到它被称为乘法时间,因为 Angular 在每个更改检测周期中评估您在模板中使用的所有表达式。变更检测周期从 ApplicationRef.tick 方法开始。
应用程序启动时 calls that tick method immediately and then it's managed by 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 模板中使用表达式来执行复杂的计算或执行副作用或 return 每次更改检测时的新值 运行。
特别是在您的代码中
<h1 *ngFor="let item of getArray()">
您在每次模板检查时都return创建一个新数组。并且 ngForOf 指令检测到您更改了数组并尝试重新呈现它(如果您的项目是对象)。
最好在代码中定义一次该数组。
arr = ['number one', 'number two']
<h1 *ngFor="let item of arr">
另一种适用于 ngForOf 指令的方法是使用 trackBy,但最好在 item 中为此设置一些唯一键。
另见
@Yurzui 的回答其实并不完全正确。这是一个例子:https://stackblitz.com/edit/angular-uqahdx
由于 Angular lifecycle hooks 的工作方式,它被多次调用。这是设置所有生命周期挂钩后页面加载的 console.log:
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
如您所见,这些日志与您的屏幕截图一致,其中有 4 次调用 getArray()
。
如果你想在你的“项目”中进行操作,你可以使用angular管道