Їй ти ідеш два рішення!
1. Змініть ChangeDetectionStrategy на OnPush
Для цього рішення ви в основному говорите кутовий:
Зупиніть перевірку на наявність змін; Я зроблю це лише тоді, коли знаю, що це необхідно
Швидке виправлення:
Змініть ваш компонент, щоб він використовувався ChangeDetectionStrategy.OnPush
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
// ...
}
З цим, схоже, щось більше не працює. Це тому, що відтепер вам доведеться здійснювати кутовий дзвінок detectChanges()
вручну.
this.cdr.detectChanges();
Ось посилання, яке допомогло мені зрозуміти права ChangeDetectionStrategy :
https://alligator.io/angular/change-detection-strategy/
2. Розуміння ExpressionChangedAfterItHasBeenCheckedError
Ось невеликий витяг з відповіді tomonari_t про причини цієї помилки, я намагався включити лише ті частини, які допомогли мені зрозуміти це.
Повна стаття показує приклади реального коду щодо кожної точки, показаної тут.
Першопричиною є кутовий життєвий цикл:
Після кожної операції Angular запам'ятовує, які значення використовував для виконання операції. Вони зберігаються у властивості oldValues перегляду компонентів.
Після перевірки всіх компонентів Angular потім починає наступний цикл дайджесту, але замість виконання операцій він порівнює поточні значення з тими, які запам'ятовується з попереднього циклу дайджесту.
Наступні операції перевіряються на циклі дайджесту:
перевірте, що значення, передані дочірнім компонентам, такі ж, як і значення, які використовувались би для оновлення властивостей цих компонентів зараз.
перевірте, що значення, використовувані для оновлення елементів DOM, такі самі, як і значення, які використовувались для оновлення цих елементів, тепер виконують ті самі.
перевірки на всі дочірні компоненти
І так, помилка кидається, коли порівняні значення відрізняються. , блогер Макс Корецький заявив:
Винуватець завжди є дочірнім компонентом чи директивою.
І, нарешті, ось кілька зразків реального світу, які зазвичай викликають цю помилку:
- Спільні послуги
- Синхронне мовлення подій
- Динамічна інстанція компонентів
Кожен зразок можна знайти тут (plunkr), в моєму випадку проблема була динамічною інстанцією компонента.
Крім того, на власному досвіді я настійно рекомендую всім уникати setTimeout
рішення, в моєму випадку спричинив "майже" нескінченну петлю (21 дзвінок, який я не бажаю показати вам, як їх спровокувати),
Я рекомендую завжди пам’ятати про кутовий життєвий цикл, щоб ви могли врахувати, як на них впливати кожен раз, коли ви змінюватимете значення іншого компонента. З цією помилкою Angular каже вам:
Ви, можливо, робите це неправильно, ви впевнені, що маєте рацію?
У цьому ж блозі йдеться також:
Часто виправленням є використання правильного гака виявлення змін для створення динамічного компонента
Короткий посібник для мене - це врахувати принаймні дві речі під час кодування ( я спробую доповнити його з часом ):
- Не змінюйте значення батьківських компонентів із компонентів його дочірніх даних, замість цього: модифікуйте їх з його батьківського.
- При використанні
@Input
і@Output
директив намагайтеся уникати спроб зміни ліфтоциклу, якщо компонент не буде повністю ініціалізований.
- Уникайте зайвих дзвінків
this.cdr.detectChanges();
вони можуть викликати більше помилок, особливо коли ви маєте справу з великою кількістю динамічних даних
- Коли використання
this.cdr.detectChanges();
обов'язкове, переконайтеся, що використовувані змінні ( @Input, @Output, etc
) заповнюються / ініціалізуються на правій гачці виявлення ( OnInit, OnChanges, AfterView, etc
)
- Коли це можливо, видаліть, а не прихойте , це пов’язано з пунктами 3 та 4.
Також
Якщо ви хочете повністю зрозуміти кутовий рятувальний гачок, рекомендую ознайомитись з офіційною документацією тут: