Angular 的 Change Detection 機制,問題: 在使用 onPush 策略時,一定都要重新傳新物件才能出發更新嗎? 答案:不用
ChangeDetecotrRef 提供了一些方法,允許我們手動觸發檢查更新機制,而 markForCheck 是其中一個
markForCheck
markForCheck 的用途,當呼叫這個方法時,就是告訴 ChangeDetector ,請檢查我本身及我上頭的 Component。更新的方向性是往 Root 向上移動
markForCheck的程式碼
1 2 3 4 5 6 7 let currView : ViewData |null = view;while (currView) { if (currView.def .flags & ViewFlags .OnPush ) { currView.state |= ViewState .ChecksEnabled ; } currView = currView.viewContainerParent || currView.parent ; }
以下提供幾個可能使用情境
使用情境
setTimeout、setInterval
可以從我之前寫的文章 溫習一下什麼是 ChangeDetectionStrategy.OnPush
當 Component 的 changeDetection 設定為 ChangeDetectionStrategy.OnPush,如果有使用 setTimeout 時,就必須配合 markForCheck() 的方法來更新 View 的顯示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import {ChangeDetectionStrategy , ChangeDetectorRef , Component , OnInit } from '@angular/core' ;@Component ({ selector : 'my-app' , templateUrl : './app.component.html' , styleUrls : [ './app.component.css' ], changeDetection : ChangeDetectionStrategy .OnPush }) export class AppComponent { vcard = [{name : 'Kevin' }]; constructor (public cd : ChangeDetectorRef ) {} ngOnInit ( ) { setTimeout (() => { this .vcard .push ({name : 'Jeff' }); }, 2000 ); } }
這裡有簡單的程式碼 可以實際執行看看,取消註解後看看執行的結果。
當 @Input 的資料型態為 Observable 再加上 onPush 時,也會有 setTimeout、setInterval 的情況出現,所以這時候也必須依賴 markForCheck 來執行顯示更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import {ChangeDetectionStrategy , ChangeDetectorRef , Component , Input , OnInit } from '@angular/core' ;import {Observable } from 'rxjs/Observable' ;@Component ({ selector : 'app-v-card' , templateUrl : './v-card.component.html' , styleUrls : ['./v-card.component.css' ], changeDetection : ChangeDetectionStrategy .OnPush }) export class VCardComponent implements OnInit { @Input () data : Observable <any >; info : any ; constructor (private cd : ChangeDetectorRef ) {} ngOnInit ( ) { this .data .subscribe (data => { this .info = data; }); } }
這裡有簡單的程式碼 可實際執行看看,取消註解後看看執行的結果。
參考資料