2017-09-06 82 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