Ее вы идете два решения!
1. Измените ChangeDetectionStrategy на OnPush
Для этого решения вы в основном говорите:
Прекратить проверку на изменения; я сделаю это только тогда, когда я знаю, что это необходимо
Быстрое решение:
Измените ваш компонент так, чтобы он использовал ChangeDetectionStrategy.OnPush
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
// ...
}
С этим вещи, кажется, больше не работают. Это потому, что теперь вам придется делать Angular вызов detectChanges()
вручную.
this.cdr.detectChanges();
Вот ссылка, которая помогла мне понять ChangeDetectionStrategy правильно:
https://alligator.io/angular/change-detection-strategy/
2. Понимание ExpressionChangedAfterItHasBeenCheckedError
Вот небольшой отрывок из ответа tomonari_t о причинах этой ошибки, я попытался включить только те части, которые помогли мне понять это.
Полная статья показывает реальные примеры кода для каждой точки, показанной здесь.
Основной причиной является угловой жизненный цикл:
После каждой операции Angular запоминает, какие значения он использовал для выполнения операции. Они хранятся в свойстве oldValues представления компонента.
После проверки всех компонентов Angular запускает следующий цикл дайджеста, но вместо выполнения операций сравнивает текущие значения с теми, которые он запомнил из предыдущего цикла дайджеста.
Следующие операции проверяются в цикле дайджеста:
убедитесь, что значения, передаваемые дочерним компонентам, совпадают со значениями, которые теперь будут использоваться для обновления свойств этих компонентов.
убедитесь, что значения, используемые для обновления элементов DOM, совпадают со значениями, которые будут использоваться для обновления этих элементов, теперь выполняются одинаково.
проверяет все дочерние компоненты
И так, ошибка выдается, когда сравниваемые значения различны. Блогер Макс Корецкий заявил:
Виновником всегда является дочерний компонент или директива.
И, наконец, вот некоторые примеры из реальной жизни, которые обычно вызывают эту ошибку:
- Общие услуги
- Синхронная трансляция событий
- Создание динамического компонента
Каждый образец можно найти здесь (plunkr), в моем случае проблема заключалась в создании динамического компонента.
Кроме того, по собственному опыту я настоятельно рекомендую всем избегать setTimeout
решения, в моем случае это вызвало «почти» бесконечный цикл (21 вызов, который я не хочу показывать вам, как их спровоцировать),
Я бы порекомендовал всегда иметь в виду жизненный цикл Angular, чтобы вы могли учитывать, как они будут влиять при каждом изменении значения другого компонента. С этой ошибкой Angular говорит вам:
Возможно, вы делаете это неправильно, вы уверены, что правы?
В том же блоге также говорится:
Часто исправление заключается в использовании правильного хука обнаружения изменений для создания динамического компонента.
Краткое руководство для меня заключается в рассмотрении по крайней мере следующих двух вещей при кодировании ( я постараюсь дополнить его с течением времени ):
- Вместо этого избегайте изменения значений родительских компонентов из дочерних компонентов: измените их из родительского.
- При использовании
@Input
и @Output
директивы пытаются избежать запуска изменений lyfecycle , если компонент не будет полностью инициализирован.
- Избегайте ненужных вызовов
this.cdr.detectChanges();
, поскольку они могут вызвать больше ошибок, особенно когда вы имеете дело с большим количеством динамических данных
- Когда использование
this.cdr.detectChanges();
является обязательным, убедитесь, что используемые переменные ( @Input, @Output, etc
) заполнены / инициализированы в правой точке обнаружения ( OnInit, OnChanges, AfterView, etc
)
- Когда это возможно, удаляйте, а не скрывайте , это относится к пунктам 3 и 4.
Также
Если вы хотите полностью понять Angular Life Hook, я рекомендую вам прочитать официальную документацию здесь: