Запустите обнаружение изменений Angular только один раз и прекратите обнаружение изменений для этого компонента.

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

На самом деле мне нужно показывать и скрывать функциональность в зависимости от роли пользователя. Итак, у меня есть много *ngIf в одном HTML-шаблоне, но мне нужно проверить условие *ngIf только один раз, когда шаблон загружается в первый раз, и перестать обнаруживать изменения после этого, потому что это влияет на производительность.

Я хочу, чтобы страница была статической после однократного обнаружения изменений.

Например :

       <li *ngIf="doesHavePermission('templateName')">
       </li>

должен проверить один раз, но я вижу, что он проверяет изменение много раз для одного *ngIf, и у меня есть много *ngIf, например:

Я нашел markForCheck() и detach() в этом документе angular https://angular.io/api/core/ChangeDetectorRef.

Но то, что они делают, так это то, что они либо разрешают обнаружение всех изменений, либо не разрешают вообще,

И мне нужно обнаружить изменения только один раз и после этого остановиться.

Можем ли мы сделать это однократное обнаружение изменения времени в angular?

Или есть лучший способ справиться со сценарием?


comment
Я рекомендую прочитать эту статью: netbasal.com/, который даст вам хороший обзор того, что возможно со стратегиями по умолчанию и onPush. К сожалению, если вы видите проблемы с производительностью, связанные с компакт-диском, это обычно означает, что ваши компоненты написаны плохо или вы имеете дело с большими объемами данных в реальном времени. OnPush — это настройка производительности, которую следует использовать с осторожностью там, где это необходимо.   -  person hevans900    schedule 17.09.2019


Ответы (2)


Когда вы используете вызов функции внутри *ngIf, angular вызывает эту функцию каждый раз, когда происходит обнаружение изменений. Неважно, запускается ли этот changeDetection снаружи или внутри вашего компонента, но angular не может знать, изменилось ли возвращаемое значение функции до того, как она вызвала эту функцию.

Таким образом, использование вызовов функций внутри *ngIf в целом не является хорошим подходом.

Альтернативы:

Используйте обычные атрибуты внутри вашего компонента:

instead of 
<div *ngIf="checkCondition()"></div>

use this

<div *ngIf="condition"></div>

@Component(...)
class MyComponent {
 condition= false;

 checkCondition() {
  if(something) {
   this.condition = true;
  }
 }
}

При таком подходе вы можете лучше справляться с изменением условия и вызывать функцию вручную. Вместо того, чтобы просто использовать атрибут, вы также можете использовать карту:

@Component(...) 
class MyComponent{
  conditions: { [key: string]: boolean }

  ngOnInit() {
   condition = {
    template1: true,
    template2: false
   }
  }
}

<div *ngIf="conditions['template1']"></div>

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

Если вы объедините эти два подхода, вы должны получить минимальное обнаружение изменений:

@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
}) 
    class MyComponent{
      @Input() conditions: { [key: string]: boolean }
}

Вот хорошая статья для дальнейшего чтения: https://medium.com/showpad-engineering/why-you-should-never-use-function-calls-in-angular-template-expressions-e1a50f9c0496

person J. S.    schedule 17.09.2019
comment
Я понял, что это хороший подход, и он приветствуется, но что, если мне нужно запустить некоторую логику, чтобы решить, истинно или ложно для * ngIf? - person Amrit; 17.09.2019
comment
либо вы запускаете эту логику внутри ngOnInit и создаете свою карту, либо в своем родительском компоненте и передаете ее через @Input - person J. S.; 17.09.2019
comment
Итак, у меня есть строка, и мне нужно проверить, присутствует ли конкретный символ в определенном индексе в этой строке на основе различных функций. Поэтому я не могу вычислить его ни в родительском, ни в ngOnInit, потому что его нужно вычислять динамически, поскольку он зависит от конкретной функциональности. Так что вы предлагаете для этого? - person Amrit; 17.09.2019
comment
Вычисление чего-либо во время выполнения является динамическим само по себе. Должен быть какой-то момент, когда у вас есть все параметры для расчета вашего состояния, и обычно это происходит до того, как вы визуализируете элементы на основе этого условия, поэтому вычисление этого в родительском элементе или ngOnint является обычным способом справиться с этим. В вашем случае я не знаю, каково ваше требование, и я не знаю вашего приложения. Может быть, вы можете предоставить stackblitz? - person J. S.; 17.09.2019

Вы можете просто использовать метод detach для ChangeDetectorRef инжектора, чтобы удалить текущий компонент из цикла обнаружения изменений. Вы всегда можете вызвать метод reattach или вручную вызвать detectChanges, чтобы быстро просмотреть изменения.

Как по мне, это самый надежный способ.

Но обратите внимание, что он всегда будет отключать обнаружение изменений для всех дочерних элементов!

person Viacheslav Muzyka    schedule 12.04.2020