Директива ngFor повторно отображает весь массив при каждой мутации?

Допустим, у нас есть массив элементов:

items = [
    { title: 'item 1'},
    { title: 'item 2'},
    /* ... */
];

И есть шаблон, который отображает этот массив:

<ul>
    <li *ngFor="let item of items">{{item.title}}</li>
</ul>

Будет ли angular2 повторно отображать весь массив, если я добавляю / удаляю элементы через _3 _ / _ 4_, или он будет только добавлять / удалять разметку для соответствующих элементов? Если он выполняет только обновления, то есть ли разница в состояниях мутации - я предпочитаю push / splice замене массива? Другими словами, эквивалентны ли эти два подхода с точки зрения производительности рендеринга:

/* 1: mutation */
this.items.push({ title: 'New Item' });

/* 2: replacement */
var newArray = this.items.slice();
newArray.push({ title: 'New Item' });

this.items = newArray;

person admax    schedule 15.02.2017    source источник


Ответы (2)


Нет , он перерисовывается только тогда, когда сам массив заменяется другим экземпляром массива.

обновить

Спасибо Оливье Буассе (см. Комментарии)

Даже когда передается другой экземпляр массива, Angular распознает, содержит ли он те же экземпляры элементов, и даже тогда не выполняет повторную визуализацию.

См. Также этот пример StackBlitz.

Если используемый IterableDiffer распознает и добавляет или удаляет в начале или в середине, то элемент вставляется / удаляется в этом месте без повторной визуализации всех остальных элементов.

Анимации, продемонстрированные в Plunkers в ответах на этот вопрос Как я могу анимировать * ngFor в angular 2? тоже это демонстрируют. Фактически, этот вид анимации был движущим фактором для реализации этого способа (в дополнение к общей оптимизации).

person Günter Zöchbauer    schedule 15.02.2017
comment
Angular не выполняет повторную визуализацию элементов, которые присутствовали в предыдущем экземпляре массива. - person Olivier Boissé; 11.12.2017
comment
@ OlivierBoissé - вот что я хочу сказать в моем ответе. Когда экземпляр массива заменяется другим с тем же содержимым, я почти уверен, что он будет полностью перерисован, иначе, как вы сказали, он будет отображать только добавленные элементы и сохранять элементы DOM для тех, которые были в массив ранее. - person Günter Zöchbauer; 11.12.2017
comment
событие с новым экземпляром, это не полностью повторно отрисовывается, я тестировал его, извлекая DOM, у меня есть новый массив, и элементы не перерисовываются, потому что они уже были там в предыдущем - person Olivier Boissé; 11.12.2017
comment
@ OlivierBoissé, у вас случайно нет примера stackblitz.com для воспроизведения? - person Günter Zöchbauer; 11.12.2017
comment
https://stackblitz.com/edit/angular-dncqm2, осмотрите первые два <p> вы увидим, что они не перерисовываются - person Olivier Boissé; 11.12.2017
comment
@ OlivierBoissé большое спасибо. Кажется, IterableDiffer был улучшен еще больше с тех пор, как я последний раз пытался. Я добавил немного CSS-анимации в приведенный вами пример, чтобы сделать его более очевидным. - person Günter Zöchbauer; 11.12.2017
comment
Я думаю, что Angular сравнивается с оператором ===, потому что, если я заменю существующие на новые объекты (с теми же свойствами / значениями), элементы будут повторно отрисованы - person Olivier Boissé; 11.12.2017
comment
Для предметов обязательно используется идентичность объекта. Обнаружение угловых изменений никогда не заботится о содержимом объекта (кроме случаев, когда оно напрямую привязано к свойству). *ngFor не зависит только от обнаружения изменений, потому что он использует IterableDiffer для поиска изменений внутри объекта (массива), но он также проверяет только идентичность объектов элементов в массиве, а не их свойства или значения. - person Günter Zöchbauer; 11.12.2017
comment
Означает ли это, что вам не нужно беспокоиться об использовании trackBy, чтобы явно указать angular, какие из них нужно повторно отрисовывать? - person Ε Г И І И О; 21.01.2021
comment
Если идентичности объекта достаточно, чтобы однозначно идентифицировать все элементы в коллекции, тогда вам не нужно trackBy, иначе вы можете указать Angular, что он должен, например, использовать свойство items id для их идентификации, например, для применения добавления / удаления / перемещения анимации. Если вы заменяете элемент в коллекции новым экземпляром, который следует рассматривать как тот же объект, используйте trackBy для Angular, чтобы иметь возможность распознать его как то же самое (например, по тому же значению свойства id) - person Günter Zöchbauer; 21.01.2021

В дополнение к ответу Гюнтера, если вы хотите знать, какая часть вашего пользовательского интерфейса отображается / повторно отображается, вы можете использовать Chrome (даже независимо от какой-либо библиотеки / фреймворка):

  • Откройте панель отладки
  • Меню (панели отладки) / Дополнительные инструменты / Рендеринг

После этого вы должны увидеть следующую панель:

введите описание изображения здесь

Включите опцию Paint Flashing и поиграйте со своим списком.
Если область мигает зеленым, она была окрашена / перекрашена ????.

ПРИМЕР: Если взять Plunkr в ответе Гюнтера: http://plnkr.co/edit/oNm5d4KwUjLpmmu4IM2K?p=preview и включите Paint Flashing, добавьте элемент в список, и вы увидите, что предыдущие элементы не мигают. (а это значит, что перекраски нет).

person maxime1992    schedule 15.02.2017