這篇大文章If you think ngDoCheck
means your component is being checked — read this article解釋錯誤的深度。
這個答案的內容是基於角版本2.x.x.有關最新版本4.x.x,請參閱this post。
沒有什麼變化檢測的內部運作在互聯網上的,所以我不得不花大約一個星期的調試來源,所以這個答案將在細節相當的技術。
角應用程序是views(AppView
類,由編譯器生成的組件特定類擴展的類)的樹。每個視圖都有一個更改檢測模式,它位於cdMode
屬性中。 cdMode
的默認值是ChangeDetectorStatus.CheckAlways
,即cdMode = 2
。
當變更檢測週期中運行,每個父視圖檢查它是否應當在子視圖here執行變化檢測:
detectChanges(throwOnChange: boolean): void {
const s = _scope_check(this.clazz);
if (this.cdMode === ChangeDetectorStatus.Checked ||
this.cdMode === ChangeDetectorStatus.Errored)
return;
if (this.cdMode === ChangeDetectorStatus.Destroyed) {
this.throwDestroyedError('detectChanges');
}
this.detectChangesInternal(throwOnChange); <---- performs CD on child view
其中this
指向child
視圖。因此,如果cdMode
爲ChangeDetectorStatus.Checked=1
,則由於該行而導致直接子女及其所有後代的變更檢測被跳過。
if (this.cdMode === ChangeDetectorStatus.Checked ||
this.cdMode === ChangeDetectorStatus.Errored)
return;
changeDetection: ChangeDetectionStrategy.OnPush
做什麼是簡單地設置cdMode
到ChangeDetectorStatus.CheckOnce = 0
,所以變化檢測後第一次運行子視圖將有其cdMode
集,因爲this code的ChangeDetectorStatus.Checked = 1
:
if (this.cdMode === ChangeDetectorStatus.CheckOnce)
this.cdMode = ChangeDetectorStatus.Checked;
這意味着,下次更改檢測週期開始時,將不會爲子視圖執行更改檢測。
有幾個選項如何運行這種視圖的變化檢測。首先是子視圖的cdMode
到ChangeDetectorStatus.CheckOnce
,可以使用this._changeRef.markForCheck()
在ngDoCheck
生命週期掛鉤進行改變:
constructor(private _changeRef: ChangeDetectorRef) { }
ngDoCheck() {
this._changeRef.markForCheck();
}
這只是改變當前視圖及其家長ChangeDetectorStatus.CheckOnce
的cdMode
,所以下一次進行變化檢測當前視圖被檢查。
檢查一個完整的例子here in the sources,但這裏是它的要點:
constructor(ref: ChangeDetectorRef) {
setInterval(() => {
this.numberOfTicks ++
// the following is required, otherwise the view will not be updated
this.ref.markForCheck();
^^^^^^^^^^^^^^^^^^^^^^^^
}, 1000);
}
第二個選項是在視圖本身呼叫detectChanges
其中當前視圖將run change detection如果cdMode
不是ChangeDetectorStatus.Checked
或ChangeDetectorStatus.Errored
。由於onPush
角度套件cdMode
到ChangeDetectorStatus.CheckOnce
,角度將運行變化檢測。
所以ngDoCheck
不會覆蓋變化的檢測,它只是要求每個被改動過的檢測週期,它是唯一的工作就是設置當前視圖cdMode
爲checkOnce
,以便在接下來的變更檢測週期它檢查的變化。詳情請參閱this answer。如果當前視圖的更改檢測模式爲checkAlways
(如果未使用onPush策略,則默認設置),ngDocCheck
似乎無用。
謝謝,但我還是不明白。你的答案似乎是關於'ngDoChanges'。它與'ngDoCheck'有什麼關係? –
@Maximus什麼意思PierreDuc如果你**不要**使用'DoCheck',你需要手動觸發變化檢測,如果對象裁判並沒有改變。 – echonax
@echonax,這更令人困惑。也許你可以展示一個精心設計的例子? –