双向Angular绑定中的ExpressionChangedAfterItHasBeenCheckedError

Est*_*ask 3 typescript angular2-changedetection angular

这是一个例子:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h1>{{ foo }}</h1>    
      <bpp [(foo)]="foo"></bpp>
    </div>
  `,
})
export class App {
  foo;
}

@Component({
  selector: 'bpp',
  template: `
    <div>
      <h2>{{ foo }}</h2>
    </div>
  `,
})
export class Bpp {
  @Input('foo') foo;

  @Output('fooChange') fooChange = new EventEmitter();

  ngAfterViewInit() {
    const potentiallyButNotNecessarilyAsyncObservable = Observable.of(null);

    potentiallyButNotNecessarilyAsyncObservable.subscribe(() => {
      this.fooChange.emit('foo');
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

偶尔出现错误的地方:

ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后发生了变化.上一个值:'undefined'.当前价值:'foo'

这是因为双向绑定由一个可以获得相同tick上的值的observable更新.我宁愿不用上面的逻辑包装,setTimeout因为它看起来像一个hack并使控制流复杂化

在这里可以做些什么来避免这个错误?

是否ExpressionChangedAfterItHasBeenCheckedError错误有不良影响还是可以忽略不计?如果可以的话,可以改变探测器是否静音并且不会污染控制台?

Max*_*kyi 6

让我们首先解开双向数据绑定以简化说明:

<div>
  <h1>{{ foo }}</h1>    
  <bpp [foo]="foo" (fooChange)="foo=$event"></bpp>
</div>
Run Code Online (Sandbox Code Playgroud)

它仍然具有相同的效果,偶尔会产生错误.只有potentiallyButNotNecessarilyAsyncObservable同步时才会产生错误.所以我们也可以替换这个:

ngAfterViewInit() {
    const potentiallyButNotNecessarilyAsyncObservable = Observable.of(null);

    potentiallyButNotNecessarilyAsyncObservable.subscribe(() => {
      this.fooChange.emit('foo');
    })
Run Code Online (Sandbox Code Playgroud)

有了这个:

ngAfterViewInit() {
    this.fooChange.emit('foo');
Run Code Online (Sandbox Code Playgroud)

这种情况属于Synchronous event broadcasting错误类别,在文章中您需要了解有关ExpressionChangedAfterItHasBeenCheckedError错误的所有内容中进行了解释.

ngAfterViewInit父组件的变化已经被处理后的生命周期钩被触发.与子组件相关的钩子的顺序在您需要了解的有关Angular中的更改检测所有内容中进行了解释.现在角度记得,改变检测的,当它跑到App成分的值fooundefined,但在验证阶段的价值是foo由子更新Bpp组件.因此它产生错误.

在这里可以做些什么来避免这个错误?

修复和问题在我链接的文章中描述.如果您不想重新设计逻辑,那么唯一安全的选择是异步更新.您还可以对父组件运行更改检测,但它们可能会导致无限循环,因为组件上的更改检测会触发组件子组件的更改检测.

ExpressionChangedAfterItHasBeenCheckedError错误会产生不良影响还是可以忽略?

不良影响是,您将在应用程序App.foo==='foo'和视图中具有不存在的状态,{{foo}}===undefined直到下一个摘要循环迭代.在开发模式下无法关闭错误,但它不会出现在生产模式中.

Angular Applications的两个阶段在解释此错误的心智模型时也相当不错.