* ngДля использования функции возвращает цикл - PullRequest
1 голос
/ 18 апреля 2019

Когда я использую * ngFor в angular с функцией, возвращающей мои данные, функция вызывается несколько раз, а иногда даже в цикле:

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>

Моя консоль:

enter image description here

Затем я получаю функцию getArray (), вызываемую несколько раз, и я не знаю, почему.

Ответы [ 2 ]

5 голосов
/ 18 апреля 2019

Обновление

Вы видите, что это называется умножением времени, потому что Angular оценивает все выражения, которые вы используете в своем шаблоне в каждом цикле обнаружения изменений. Цикл обнаружения изменений начинается с метода ApplicationRef.tick .

Когда приложение запускается, вызывает этот тиковый метод немедленно, а затем оно управляется ngZone.onMicrotaskEmpty подпиской.

Дополнительно, каждый тиковый метод выполняет дополнительную проверку 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, но для этого лучше иметь некоторый уникальный ключ в элементе.

Смотри также

2 голосов
/ 18 апреля 2019

@ Ответ Юрзуи на самом деле не совсем правильный.Вот пример: https://stackblitz.com/edit/angular-uqahdx

Он вызывается несколько раз из-за работы Angular ловушек жизненного цикла .Это файл 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().

...