请向我解释为什么我一直得到这个错误:ExpressionChangedAfterItHasBeenCheckedError:表达式已经改变后,它被检查。
显然,我只有在开发模式下才会遇到这种情况,在我的产品构建中不会出现这种情况,但这非常烦人,而且我根本不明白在我的开发环境中出现错误而不会在prod上显示的好处——可能是因为我缺乏理解。
通常,修复很简单,我只是把导致错误的代码包装在setTimeout中,就像这样:
setTimeout(()=> {
this.isLoading = true;
}, 0);
或者使用如下构造函数强制检测更改:
this.isLoading = true;
this.cd.detectChanges();
但是为什么我总是遇到这个错误呢?我想要了解它,这样我就可以在将来避免这些俗套的修复。
尝试了上面建议的大部分解决方案。只有在这种情况下对我有用。我使用*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生命周期钩子必然会引起性能问题,因为你的应用程序会越来越大,因为它会被多次触发。
有一些有趣的答案,但我似乎没有找到一个符合我的需求,最接近的是来自@chittrang-mishra,它只指一个特定的功能,而不是像我的应用程序中那样有几个切换。
我不想使用[隐藏]利用*ngIf甚至不是DOM的一部分,所以我找到了以下解决方案,这可能不是最好的,因为它抑制错误而不是纠正它,但在我的情况下,我知道最终结果是正确的,这似乎对我的应用程序是可以的。
我所做的是实现AfterViewChecked,添加构造函数(私有changeDetector: ChangeDetectorRef){},然后
ngAfterViewChecked(){
this.changeDetector.detectChanges();
}
我希望这能帮助到其他人,就像其他人帮助过我一样。
一旦我理解了Angular生命周期钩子以及它们与变更检测的关系,我就理解了很多。
我试图让Angular更新一个绑定到元素的*ngIf的全局标志,我试图在另一个组件的ngOnInit()生命周期钩子中更改这个标志。
根据文档,这个方法会在Angular检测到变化之后调用:
在第一个ngOnChanges()之后调用一次。
因此,在ngOnChanges()中更新标志不会启动变更检测。然后,一旦变更检测再次自然触发,标志的值就发生了变化,并抛出错误。
在我的例子中,我修改了这个:
constructor(private globalEventsService: GlobalEventsService) {
}
ngOnInit() {
this.globalEventsService.showCheckoutHeader = true;
}
:
constructor(private globalEventsService: GlobalEventsService) {
this.globalEventsService.showCheckoutHeader = true;
}
ngOnInit() {
}
它解决了这个问题:)