繁体   English   中英

ExpressionChangedAfterItHasBeenCheckedError:检查后表达式已更改 - 如何在可观察值更改后更新模板

[英]ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked - How to update template after Observable Value change

我浏览了很多 SO 帖子,试图找到解决这个问题的方法,我发现唯一一个有 hack 实现的帖子。 我也有一个来自我订阅的 ngrx 商店的可观察对象:

this.navigationSelected$ = this.store.pipe(select(currentlySelectedNavigation));

this.navigationSelected$.subscribe(res => {
  ...
});

使用 ngIf 取决于模板内的这个可观察值:

<profile-navigation *ngIf="(navigationSelected$ | async) == navigationLayout[0].location"></profile-navigation>

每当 navigationSelected$ 的值发生变化时,就会抛出:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: [object Object]'. Current value: 'ngIf: false'.

并且模板不会更新。 我设法通过运行 cdRef.detectChanges(); 绕过它。 在订阅结束时。 它工作正常,但仍然抛出错误,而且如上所述,它似乎是一个黑客。

实现我想要做的事情的最佳方法是什么?

我通常添加一个 debounceTime(0) 来解决这个问题。

this.navigationSelected$ = this.store.pipe(select(currentlySelectedNavigation), debounceTime());

每当 navigationSelected$ 的值发生变化时,就会抛出:

该错误意味着该值更改了两次。

当您在选择器上出现这些错误时,修复它们可能非常困难。 景色真的没有什么问题。 问题是 store 在渲染视图之前和之后更改状态,这可能意味着在调用setTimeout()之后应该发生调度。

问题是这使得源代码中的其他地方依赖于更改状态以保护视图免于触发错误。 这并不理想。

另一种方法是使用EventEmitter发出值。

<profile-navigation *ngIf="(navigationSelectedSafe$ | async) == navigationLayout[0].location"></profile-navigation>

public navigationSelectedSafe$ = new EventEmitter<any>(true); // must be true

this.navigationSelected$.subscribe(res => navigationSelectedSafe$.emit(res));

当您使用EventEmitter(true) ,它将在setTimeout()之后发出值,以保护视图免受更改错误的影响。

您还可以在源代码中搜索使用@Output() ,看看将其更改为EventEmitter(true)解决问题。

通常当您在选择器上看到此错误时。 这意味着您在视图之外做了很多与状态相关的工作。 需要广播某些内容已更改的组件应该使用@Output()但如果该组件正在调度,则它会绕过视图过程。 这是您遇到这些问题的地方。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM