请向我解释为什么我一直得到这个错误:ExpressionChangedAfterItHasBeenCheckedError:表达式已经改变后,它被检查。
显然,我只有在开发模式下才会遇到这种情况,在我的产品构建中不会出现这种情况,但这非常烦人,而且我根本不明白在我的开发环境中出现错误而不会在prod上显示的好处——可能是因为我缺乏理解。
通常,修复很简单,我只是把导致错误的代码包装在setTimeout中,就像这样:
setTimeout(()=> {
this.isLoading = true;
}, 0);
或者使用如下构造函数强制检测更改:
this.isLoading = true;
this.cd.detectChanges();
但是为什么我总是遇到这个错误呢?我想要了解它,这样我就可以在将来避免这些俗套的修复。
此错误表明应用程序中存在真正的问题,因此抛出异常是有意义的。
在devMode中,更改检测在每次常规的更改检测运行之后增加一个额外的回合,以检查模型是否已更改。
如果模型在常规变化检测轮和附加变化检测轮之间发生了变化,则这表明也发生了变化
变更检测本身导致了变更
每次调用方法或getter都会返回不同的值
这两个都不好,因为不清楚如何继续,因为模型可能永远不会稳定。
如果Angular一直运行变更检测直到模型稳定,那么它可能会一直运行下去。
如果Angular不运行变更检测,那么视图可能不会反映模型的当前状态。
参见Angular2中生产模式和开发模式的区别是什么?
尝试了上面建议的大部分解决方案。只有在这种情况下对我有用。我使用*ngIf来切换角材料的不确定渐进条基于api调用,它抛出ExpressionChangedAfterItHasBeenCheckedError。
在上述组件中:
constructor(
private ngZone: NgZone,
private changeDetectorRef: ChangeDetectorRef,
) {}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.appService.appLoader$.subscribe(value => {
this.loading = value;
this.changeDetectorRef.detectChanges();
});
});
}
诀窍是使用ngzone绕过角分量的变化检测。
PS:不确定这是否是一个优雅的解决方案,但是使用AfterContentChecked和AfterViewChecked生命周期钩子必然会引起性能问题,因为你的应用程序会越来越大,因为它会被多次触发。