簡體   English   中英

角查詢列表更改事件ExpressionChangedAfterItHaHasBeenCheckedError

[英]Angular QueryList change event ExpressionChangedAfterItHasBeenCheckedError

訂閱QueryList時,更改事件,對事件作出反應並更改視圖綁定到的屬性。 我得到一個ExpressionChangedAfterItHaHasBeenCheckedError,該值類似於舊值。

我做了一個stackblitz 示例,顯示了錯誤。

我可以通過在隊列中添加微任務來解決它。 但是我只是想了解正在發生的事情。

謝謝

這是發生了什么事;

在開發方式下,如本文“ 相關更改檢測操作”部分所述,發生兩個連續的CD周期;

正在運行的Angular應用程序是一棵組件樹。 在變更檢測期間,Angular對每個組件執行檢查,該組件包括按指定順序執行的以下操作:

  1. 更新所有子組件/指令的綁定屬性
  2. 在所有子組件/指令上調用ngOnInit,OnChanges和ngDoCheck生命周期掛鈎
  3. 更新當前組件的DOM
  4. 對子組件運行更改檢測
  5. 為所有子組件/指令調用ngAfterViewInit生命周期掛鈎
  • 單擊添加按鈕后,單擊回調完成后,將開始執行更改檢測。 comp有1個元素
  • 在第一個CD周期中; DOM在步驟更新在第3元素comp添加到DOM以及{{ count.length }}被投射到DOM作為0
  • @ViewChildren('comp') test: QueryList<ElementRef> 步驟5 之前更新test: QueryList有1個元素
  • 設置ViewChildren查詢時,同時在步驟5之前,同時發出QueryList.changes observable。this.count.push this.count.push(this.test.length)被執行, count.length變為1。
  • ngAfterViewChecked被執行,第一張CD(我們調查的相關部分)結束
  • 第二個CD循環開始。 在此循環中,角度檢查當前狀態下第一CD循環的先前值。
  • 在此檢查期間,它遇到{{ count.length }}投影到DOM的值為0,但現在count.length為1的情況。此時,它將引發異常。

解釋更多; {{ count.length }}更改為{{ count }}不會引發錯誤,因為對象引用沒有改變。

同樣 {{ count.length }}更改為{{ comps.length }}也不會引發錯誤,因為在第一個CD周期開始之前comps.length也為1。

我還創建了一個演示,該演示在與我們的調查有關的組件生命周期中打印相關步驟。 您可以看到在第四個CD周期開始之前引發了異常。 (第一個和第二個CD循環發生在單擊按鈕之前,因此應注意演示第三個和第4個CD循環)。 還應注意QueryList.changes發出值的地方。

https://stackblitz.com/edit/angular-tmcttm

最后,正如您所說,解決此特定問題的方法是通過更改此行將微任務添加到隊列中

this.count.push(this.test.length);

進入這個

setTimeout(_ => this.count.push(this.test.length));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM