2

我浏览了很多 SO 帖子,试图找到解决这个问题的方法,我发现唯一一个有 hack 实现的帖子。我也订阅了从 ngrx 商店获取的 observable:

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(); 绕过它。在订阅结束时。它工作正常,但错误仍然被抛出,而且如上所述,它似乎是一个 hack。

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

4

2 回答 2

5

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

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

于 2020-07-10T07:02:48.253 回答
2

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

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

当您在选择器上出现这些错误时,可能很难修复它们。观点确实没有什么问题。问题是商店在视图渲染之前和之后都在改变状态,这可能意味着在setTimeout()调用 a 之后应该发生调度。

问题在于,这使得源代码中的某些其他位置依赖于更改状态以保护视图不触发错误。这并不理想。

另一种方法是使用 发出值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)它时,它会在 a 之后发出值,setTimeout()从而保护视图免受更改错误的影响。

您还可以在您的源代码中搜索您使用的地方,@Output()看看是否更改它以EventEmitter(true)解决问题。

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

于 2019-06-13T14:18:05.753 回答