请向我解释为什么我一直得到这个错误:ExpressionChangedAfterItHasBeenCheckedError:表达式已经改变后,它被检查。

显然,我只有在开发模式下才会遇到这种情况,在我的产品构建中不会出现这种情况,但这非常烦人,而且我根本不明白在我的开发环境中出现错误而不会在prod上显示的好处——可能是因为我缺乏理解。

通常,修复很简单,我只是把导致错误的代码包装在setTimeout中,就像这样:

setTimeout(()=> {
    this.isLoading = true;
}, 0);

或者使用如下构造函数强制检测更改:

this.isLoading = true;
this.cd.detectChanges();

但是为什么我总是遇到这个错误呢?我想要了解它,这样我就可以在将来避免这些俗套的修复。


当前回答

参考文章https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4

因此,变更检测背后的机制实际上是以同步执行变更检测和验证摘要的方式工作的。这意味着,如果我们异步更新属性,当验证循环运行时,值不会被更新,我们也不会得到ExpressionChanged…错误。我们得到这个错误的原因是,在验证过程中,Angular看到的值与它在变更检测阶段记录的值不同。所以为了避免....

1)使用changeDetectorRef

2)使用setTimeOut。这将在另一个VM中作为宏任务执行您的代码。Angular在验证过程中不会看到这些更改,你也不会得到这个错误。

 setTimeout(() => {
        this.isLoading = true;
    });

3)如果你真的想在相同的虚拟机上执行你的代码使用

Promise.resolve(null).then(() => this.isLoading = true);

这将创建一个微任务。微任务队列是在当前同步代码完成执行之后处理的,因此对属性的更新将在验证步骤之后发生。

其他回答

解决方案…服务和rxjs…事件发射器和属性绑定都使用rxjs..你最好自己实现它,更多的控制,更容易调试。记住,事件发射器使用rxjs。简单地说,创建一个服务,并在一个可观察对象中,让每个组件订阅该观察对象,并根据需要传递新值或消耗值

我也遇到过类似的问题。查看生命周期钩子文档,我将ngAfterViewInit更改为ngAfterContentInit,它工作正常。

有一些有趣的答案,但我似乎没有找到一个符合我的需求,最接近的是来自@chittrang-mishra,它只指一个特定的功能,而不是像我的应用程序中那样有几个切换。

我不想使用[隐藏]利用*ngIf甚至不是DOM的一部分,所以我找到了以下解决方案,这可能不是最好的,因为它抑制错误而不是纠正它,但在我的情况下,我知道最终结果是正确的,这似乎对我的应用程序是可以的。

我所做的是实现AfterViewChecked,添加构造函数(私有changeDetector: ChangeDetectorRef){},然后

ngAfterViewChecked(){
  this.changeDetector.detectChanges();
}

我希望这能帮助到其他人,就像其他人帮助过我一样。

我在RxJS/Observables和静态模拟数据之间有这个问题。首先,我的应用程序使用静态模拟数据,在我的例子中是数据数组

html是这样的:

*ngFor="let x of myArray?.splice(0, 10)"

我们的想法是只显示myArray中的10个元素。Splice()获取原始数组的副本。据我所知,这在Angular中是完全没问题的。

然后我把数据流改为Observable模式,因为我的“真实”数据来自Akita(一个状态管理库)。这意味着我的html变成:

*ngFor="let x of (myArray$ | async)?.splice(0, 10)"

where myArray$是[was]类型的Observable<MyData[]>,这个模板中的数据操作是导致错误发生的原因。不要对RxJS对象这样做。

以下是我对正在发生的事情的看法。我还没有阅读文档,但我确信这是错误显示的部分原因。

*ngIf="isProcessing()" 

当使用*ngIf时,它会在每次条件改变时通过添加或删除元素来物理地改变DOM。因此,如果条件在呈现给视图之前发生了变化(这在Angular的世界中是极有可能的),就会抛出错误。请参阅开发和生产模式之间的解释。

[hidden]="isProcessing()"

当使用[hidden]时,它不会在物理上改变DOM,而只是从视图中隐藏元素,很可能在后面使用CSS。元素仍然在DOM中,但不可见,这取决于条件的值。这就是为什么使用[hidden]时不会出现错误的原因。