Angular перерисовывает, когда пользователь наводит курсор на карту Openlayers

Я использую Openlayers 6 в своем проекте вместе с Angular 8. И до сих пор я замечал, что всякий раз, когда я наводил курсор на карту Openlayers, компонент Angular, на котором расположена карта, перерисовывается.

Мой вопрос в том, как заставить родительский компонент постоянно переставлять рендеринг при наведении курсора. Потому что это замедляет работу приложения. В моем проекте есть гораздо более крупный компонент, и из-за этого повторный рендеринг всего сделает само приложение медленнее.

Для этого я создал репо, чтобы продемонстрировать это: https://github.com/petrovichm/angular-openlayers-hover-problem. В этом примере я добавил метод в html, который будет регистрировать, когда он запускается, таким образом давая обзор, сколько раз угловой компонент повторного рендеринга.

Я хотел создать онлайн-запуск с помощью plunker илиcodeanbox, но когда я делаю этот пример, окно зависает из-за бесконечного цикла повторного рендеринга, что делает их непригодными для использования, на самом деле этого не происходит, когда я запускаю этот проект локально, это происходит только на парить

Спасибо.


person Mario Petrovic    schedule 07.02.2020    source источник
comment
Пробовали ли вы использовать стратегию обнаружения изменений при нажатии, чтобы предотвратить это? @Component({ ..., changeDetection: ChangeDetectionStrategy.OnPush }) Это должно предотвратить проблему, о которой вы говорите.   -  person Daniel W Strimpel    schedule 08.02.2020
comment
Да, я это сделал, он все еще перерисовывается.   -  person Mario Petrovic    schedule 08.02.2020


Ответы (1)


После клонирования вашего репо, чтобы посмотреть на вещи, есть две вещи.

Во-первых, вариант использования очень прост, поэтому вы не увидите всех преимуществ от использования стратегии обнаружения изменений по нажатию, которая смягчает большую часть этой проблемы, поскольку она не приведет к тому, что у некорневых компонентов будет цикл обнаружения изменений (если все компоненты используют стратегию включения (то есть).

Во-вторых, поскольку базовая библиотека карт (OpenLayers) присоединяет события к самим узлам DOM, это приведет к срабатыванию обнаружения изменений Angular из-за того, что zone.js перехватывает обработку событий. Чтобы этого не произошло, вам придется настроить карту вне зоны Angular:

import { ..., NgZone } from '@angular/core';

...
export class AppComponent implements OnInit {
  ...

  construtor(private zone: NgZone) {
  }

  ...

  ngOnInit() {
    this.zone.runOutsideAngular(() => {
      this.map = new Map({ ... });
    });
  }
}

Вы должны быть осторожны при запуске чего-либо за пределами зоны Angular, но здесь имеет смысл сделать это, чтобы предотвратить ваши проблемы. Вам нужно будет обернуть любую логику обработки событий вашей карты обратно в зону Angular, чтобы Angular знал об обновлениях.

export class AppComponent implements OnInit {
  currentValue = 0;

  ...

  ngOnInit() {
    this.zone.runOutsideAngular(() => {
      this.map = new Map({ ... });
    });

    this.map.on('click', (e) => {
      this.currentValue++; // Angular will not pick up this change because it will run outside of the Angular zone
    });

    this.map.on('click', (e) => {
      this.zone.run(() => {
        this.currentValue++; // Angular will pick up this change because it will run inside the Angular zone
      });
    });
  }
}

Вот хороший пост в блоге, который, я думаю, может помочь понять это: https://netbasal.com/optimizing-angular-change-detection-triggered-by-dom-events-d2a3b2e11d87.

person Daniel W Strimpel    schedule 07.02.2020
comment
Привет, чувак, спасибо за подсказку. Я попробую это сделать на следующей неделе и тогда дам вам отзыв. Я не знала, что можно вот так оторваться от зоны. Я сделал это с помощью служебного метода DetecChanges.detach (). Но и с этим не сработало. Спасибо еще раз - person Mario Petrovic; 08.02.2020
comment
Это решение действительно работает. Спасибо за Ваш ответ. Это сделает более крупный шаблон, но, эй, это определенно ускорит приложение. - person Mario Petrovic; 13.02.2020