给你两种解决方案!
1. 修改ChangeDetectionStrategy为OnPush
对于这个解决方案,你基本上告诉angular:
停止检查变更;我只会在必要的时候做
修改组件,使其使用ChangeDetectionStrategy。OnPush是这样的:
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
// ...
}
有了这个,事情似乎就不管用了。这是因为从现在开始,你必须让Angular手动调用detectChanges()。
this.cdr.detectChanges();
如果你感兴趣,请查看这篇文章。它帮助我理解了ChangeDetectionStrategy是如何工作的。
2. 理解ExpressionChangedAfterItHasBeenCheckedError
请查看关于这个问题的视频(太棒了!)此外,这里是本文中关于此错误原因的一小部分摘录,我试图只包括有助于我理解此错误的部分。
整篇文章给出了关于这里所示的每一点的真实代码示例。
根本原因是angular生命周期的问题:
在每个操作之后,Angular都会记住它执行了什么值
一个操作。属性的oldValues属性中存储
组件视图。
检查完所有组件后,Angular就会启动
下一个摘要周期,但它不执行操作,而是将当前值与它记忆的值进行比较
前一个消化周期。
在摘要周期中检查以下操作:
检查传递给子组件的值是否与
用于更新这些组件属性的值
现在。
检查用于更新DOM元素的值是否与
用于更新这些元素的值现在执行
相同。
检查所有子组件
因此,当比较值不同时,就会抛出错误。,博主Max Koretskyi表示:
罪魁祸首总是子组件或指令。
最后,这里有一些现实世界中通常会导致这种错误的例子:
共享服务(示例)
同步事件广播(示例)
动态组件实例化(示例)
在我的例子中,问题是动态组件实例化。
此外,从我自己的经验来看,我强烈建议大家避免使用setTimeout解决方案,在我的情况下会导致“几乎”无限循环(21个调用,我不愿意向您展示如何激发它们),
我建议你时刻牢记Angular的生命周期,这样你就可以在每次修改另一个组件的值时考虑到它们会受到怎样的影响。对于这个错误,Angular会告诉你:
你可能做错了,你确定你是对的吗?
该博客还写道:
通常,解决方法是使用正确的更改检测钩子来创建动态组件
对我来说,一个简短的指南是在编码时至少考虑以下事情:
(我会尽量补充这一点):
Avoid modifying parent component values from its child's components,
instead: modify them from their parent.
When you use @Input and @Output directives try to avoid triggering lifecycle changes unless the component is completely initialized.
Avoid unnecessary calls of this.cdr.detectChanges(); they can trigger more errors, especially when you're dealing with a lot of dynamic data
When the use of this.cdr.detectChanges(); is mandatory make sure that the variables (@Input, @Output, etc) being used are filled/initialized at the right detection hook (OnInit, OnChanges, AfterView, etc)
When possible, remove rather than hide, this is related to point 3 and 4. (same quote for angulardart)
Avoid any kind of logic inside setters annotated with @Input, setters are executed previously to ngAfterViewInit so it'll easily trigger the issue. In case you need to, its better of to put that logic inside the ngOnChanges method.
Also
如果你想完全理解Angular Life Hook,我建议你阅读这里的官方文档:
https://angular.io/guide/lifecycle-hooks