Sie gehen zwei Lösungen!
1. Ändern Sie ChangeDetectionStrategy in OnPush
Für diese Lösung sagen Sie im Grunde eckig:
Hören Sie auf, nach Änderungen zu suchen. Ich werde es nur tun, wenn ich weiß, dass es notwendig ist
Die schnelle Lösung:
Ändern Sie Ihre Komponente so, dass sie verwendet wird ChangeDetectionStrategy.OnPush
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
// ...
}
Damit scheinen die Dinge nicht mehr zu funktionieren. Das liegt daran, dass Sie Angular von nun an detectChanges()
manuell aufrufen müssen.
this.cdr.detectChanges();
Hier ist ein Link, der mir geholfen hat, ChangeDetectionStrategy richtig zu verstehen :
https://alligator.io/angular/change-detection-strategy/
2. Grundlegendes zu ExpressionChangedAfterItHasBeenCheckedError
Hier ist ein kleiner Auszug aus der Antwort von tomonari_t über die Ursachen für diesen Fehler. Ich habe versucht, nur die Teile einzubeziehen , die mir geholfen haben, dies zu verstehen.
Der vollständige Artikel zeigt echte Codebeispiele zu jedem hier gezeigten Punkt.
Die Hauptursache ist der Winkellebenszyklus:
Nach jeder Operation merkt sich Angular, welche Werte zur Ausführung einer Operation verwendet wurden. Sie werden in der Eigenschaft oldValues der Komponentenansicht gespeichert.
Nachdem die Überprüfungen für alle Komponenten durchgeführt wurden, startet Angular den nächsten Digest-Zyklus. Statt jedoch Vorgänge auszuführen, werden die aktuellen Werte mit denen verglichen, an die er sich aus dem vorherigen Digest-Zyklus erinnert.
Die folgenden Vorgänge werden bei Digest-Zyklen überprüft:
Überprüfen Sie, ob die an die untergeordneten Komponenten übergebenen Werte mit den Werten übereinstimmen, mit denen die Eigenschaften dieser Komponenten jetzt aktualisiert werden.
Überprüfen Sie, ob die zum Aktualisieren der DOM-Elemente verwendeten Werte mit den Werten übereinstimmen, die zum Aktualisieren dieser Elemente verwendet werden.
prüft auf alle untergeordneten Komponenten
Und so wird der Fehler ausgelöst wird, wenn die verglichenen Werte unterschiedlich sind. , erklärte Blogger Max Koretskyi :
Der Schuldige ist immer die untergeordnete Komponente oder eine Richtlinie.
Und schließlich sind hier einige Beispiele aus der Praxis, die normalerweise diesen Fehler verursachen:
- Geteilte Dienstleistungen
- Synchrone Ereignisübertragung
- Dynamische Komponenteninstanziierung
Jedes Beispiel finden Sie hier (plunkr). In meinem Fall war das Problem eine dynamische Komponenteninstanziierung.
Aus eigener Erfahrung empfehle ich jedem dringend, die setTimeout
Lösung zu vermeiden . In meinem Fall kam es zu einer "fast" Endlosschleife (21 Anrufe, die ich Ihnen nicht zeigen möchte, wie man sie provoziert).
Ich würde empfehlen, immer die Winkellebenszyklen im Auge zu behalten, damit Sie berücksichtigen können, wie sie sich jedes Mal auswirken, wenn Sie den Wert einer anderen Komponente ändern. Mit diesem Fehler sagt Ihnen Angular:
Du machst das vielleicht falsch, bist du sicher, dass du Recht hast?
Der gleiche Blog sagt auch:
Häufig besteht die Lösung darin, den richtigen Änderungserkennungs-Hook zu verwenden, um eine dynamische Komponente zu erstellen
Eine kurze Anleitung für mich ist, beim Codieren mindestens die folgenden zwei Dinge zu berücksichtigen ( ich werde versuchen, sie im Laufe der Zeit zu ergänzen ):
- Vermeiden Sie es, übergeordnete Komponentenwerte aus den untergeordneten Komponenten zu ändern. Ändern Sie sie stattdessen über die übergeordneten Komponenten.
- Wenn Sie
@Input
und @Output
Direktiven verwenden, versuchen Sie zu vermeiden, dass Lyfecycle-Änderungen ausgelöst werden, es sei denn, die Komponente ist vollständig initialisiert.
- Vermeiden Sie unnötige Aufrufe, da
this.cdr.detectChanges();
diese mehr Fehler auslösen können, insbesondere wenn Sie mit vielen dynamischen Daten arbeiten
- Wenn die Verwendung von
this.cdr.detectChanges();
obligatorisch ist, stellen Sie sicher, dass die verwendeten Variablen ( @Input, @Output, etc
) am rechten Erkennungshaken ( OnInit, OnChanges, AfterView, etc
) gefüllt / initialisiert sind.
- Wenn möglich, entfernen statt verstecken , dies bezieht sich auf Punkt 3 und 4.
Ebenfalls
Wenn Sie Angular Life Hook vollständig verstehen möchten, empfehle ich Ihnen, die offizielle Dokumentation hier zu lesen: