2017-09-06 43 views
3

下面是一个exampleExpressionChangedAfterItHasBeenCheckedError双向角结合

@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'); 
    }) 
    } 
} 

其中的错误,偶尔会出现:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'foo'

它的事实,双向绑定是通过观察到更新的结果,可以在相同的勾号上获得价值。我宁愿不用上面的逻辑来包装setTimeout,因为它看起来像一个黑客行为并使控制流程变得复杂了。

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

ExpressionChangedAfterItHasBeenCheckedError错误是否有不良影响或可以忽略?如果可以的话,可以改变探测器对其进行沉默而不污染控制台?

+0

我从来没有得到那个错误,但你有没有尝试过使用异步管道?可能会有所帮助。 – fastAsTortoise

+0

@fastAsTortoise此处不适用管道无论模板如何,都会显示错误。 – estus

回答

4

让我们先来解开双向数据绑定,以简化的解释:

<div> 
    <h1>{{ foo }}</h1>  
    <bpp [foo]="foo" (fooChange)="foo=$event"></bpp> 
</div> 

它仍然有同样的效果,有时会产生误差。只有在potentiallyButNotNecessarilyAsyncObservable是同步的情况下才会产生错误。所以,我们也可以取代这个:

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

    potentiallyButNotNecessarilyAsyncObservable.subscribe(() => { 
     this.fooChange.emit('foo'); 
    }) 

与此:

ngAfterViewInit() { 
    this.fooChange.emit('foo'); 

此情况下落入错误的Synchronous event broadcasting的类别,是文章Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error中解释。

在处理父组件更改后触发ngAfterViewInit生命周期挂钩。在Everything you need to know about change detection in Angular中解释了与子组件相关的钩子顺序。现在Angular记得当它运行App组件的变更检测时,foo的值为undefined,但在验证阶段中,值为foo,该值由子组件Bpp更新。因此它会产生错误。

What can be done to avoid this error here?

修复和问题在文章I链接中描述。如果你不想重新设计你的逻辑,这里唯一的安全选择就是异步更新。您也可以运行父组件的变更检测,但它们可能会导致无限循环,因为组件的变更检测会触发组件子项的变更检测。

Does ExpressionChangedAfterItHasBeenCheckedError error have ill effects or can it be ignored?

的不良影响是,你将不得不在应用App.foo==='foo',直到下一次迭代digest cycle视图{{foo}}===undefined incosistent状态。该错误在开发模式下无法关闭,但不会出现在生产模式中。

Two Phases of Angular Applications也很好的解释了这个错误的心理模型。

+1

希望我能够百万次提高这一点。 – paqogomez