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

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

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

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

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

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

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


当前回答

在@ViewChild装饰器中添加static: true

@ViewChild(UploadComponent, { static: true }) uploadViewChild: UploadComponent;

其他回答

我在Ionic3(它使用Angular 4作为其技术堆栈的一部分)中遇到过这种错误。

对我来说,它是这样的:

< ion-icon[名字]= " getFavIconName ()" > < / ion-icon >

所以我试着有条件地改变离子图标的类型,从大头针到删除圈,根据屏幕运行的模式。

我猜我将不得不添加一个*ngIf代替。

我在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对象这样做。

如果你在ngAfterViewInit()中触发EventEmitter时看到ExpressionChangedAfterItHasBeenCheckedError,那么你可以在创建EventEmitter时传递true,使其在当前更改检测周期后异步发射。

@Component({
  ...
})
export class MyComponent implements AfterViewInit {
  // Emit asynchronously to avoid ExpressionChangedAfterItHasBeenCheckedError
  @Output() valueChange = new EventEmitter<number>(true);

  ...

  ngAfterViewInit(): void {
    ...
    this.valueChange.emit(newValue);
    ...
  }

}

我使用的是ng2-carouselamos (Angular 8和Bootstrap 4)

下面这些步骤解决了我的问题:

实现AfterViewChecked 添加构造函数(私有changeDetector: ChangeDetectorRef) {} 然后ngAfterViewChecked(){this.changeDetector.detectChanges();}

我得到这个错误,因为我在component.html中使用了一个没有在component.ts中声明的变量。一旦我删除了HTML中的部分,这个错误就消失了。