angular11原始碼探索[DoCheck 生命週期和onChanges區別]

房東家的貓發表於2020-11-27

原理圖

直接生成模組和路由然後定義宣告的模組

ng g m  one --routing --m=app

元件+模組+路由+指向的宣告路徑

ng g m two --route=home  --m=app

生命週期 DoCheck 和 onChanges 的區別

當我們傳入陣列或者物件的時候,我們會發現子元件的onChanges 檢測不到變化

這時候我們可以用DoCheck 來監控變化了

父元件,當點選的時候給父元件

export class TwoComponent implements OnInit {
  public arr: Array<any> = ['a', 'b', 'c']
  obj: object = {
    name: 'xxx',
    age: 'bbb'
  };

  constructor() {
  }


  ngOnInit(): void {
  }

  public i: number = 0;

  clickMethod(): void {
    this.arr.push(this.arr.length)
    this.obj[this.i++] = this.i;
  }
}
<button (click)="clickMethod()">++</button>
<app-user [sex]="arr" [videos]="obj"></app-user>

子元件

只要執行更改檢測,就會呼叫 ngDoCheck()

export class UserComponent implements OnInit,OnChanges,DoCheck {
  @Input('sex') sex;
  @Input('videos') videos;
 // 可以解構拿到需要修改的屬性
  ngOnChanges({sex,videos}: SimpleChanges) {
    console.log(sex);
    console.log(videos);
  }
  ngDoCheck() {
    console.log(this.videos);
  }
}

我們會發現ngOnChanges子元件除了第一次傳遞的時候能監控到變化,當修改的時候監控不到

但是我們會發現ngDoCheck 在修改的時候能監控到物件的變化

ngOnChanges 用於 基本資料型別

ngDoCheck 用於引用資料型別

KeyValueDiffers

KeyValueDiffers是不同地圖差異策略的儲存庫。角內部使用它的指令NgClassNgStyle等等。無論何時,只要結合這些指令值的變化,這些變化體現。為了處理和更新更改,Angular使用KeyValueDiffers

1. KeyValueDiffers可以使用建構函式注入到元件中。

constructor(private kvDiffers: KeyValueDiffers) {} 

2. KeyValueDiffers提供find方法。

    find(kv: any): KeyValueDifferFactory;

kv:傳遞需要檢測以進行更改的物件。
find方法返回KeyValueDifferFactory

3. KeyValueDifferFactory提供工廠KeyValueDiffer。要獲取KeyValueDiffer例項,請KeyValueDifferFactory提供create方法。

    create<K, V>(): KeyValueDiffer<K, V>;

4. KeyValueDiffer與眾不同之處是跟蹤物件隨時間的變化。它具有一種diff計算先前狀態和新物件狀態之間的差異的方法。

    diff(object: Map<K, V>): KeyValueChanges<K, V> | null;

5. KeyValueChanges自上次diff呼叫該方法以來,將更改保留在對映中。KeyValueChanges有以下方法。
forEachItem:遍歷所有更改。
forEachPreviousItem:迭代已更改的先前專案。
forEachChangedItem:迭代其值已更改的那些項。
forEachAddedItem:遍歷所有新增的專案。
forEachRemovedItem:遍歷所有已刪除的專案。
上述所有KeyValueChanges提供KeyValueChangeRecord專案的方法都是迭代的。

6. KeyValueChangeRecord是表示專案更改資訊的記錄。KeyValueChangeRecord具有諸如currentValuepreviousValue。要獲取當前值,我們將其稱為currentValue屬性,並獲取先前值,我們將其稱為previousValue屬性。找到程式碼段。

    readonly key: K;
    readonly currentValue: V | null;
    readonly previousValue: V | null;

完整的例子

export class UserComponent implements OnInit, OnChanges, DoCheck {
  @Input('sex') sex;
  @Input('videos') videos;
  public differs

  // 可以解構拿到需要修改的屬性,一般用於基本資料型別
  ngOnChanges({sex, videos}: SimpleChanges) {
    // console.log(sex);
    // console.log(videos);
  }
  ngDoCheck() {
    let mpArray = this.differs.diff(this.sex)
    if (mpArray) {
      // 變化檢測
      mpArray.forEachAddedItem(record => {
        console.log('增加', record);
      })
      mpArray.forEachChangedItem(record => {
        console.log('更改', record);
      })
      mpArray.forEachRemovedItem(record => {
        console.log('刪除', record);
      })
      /*有變動的時候,顯示原始所有值*/
      mpArray.forEachPreviousItem(record => {
        // console.log('之前的',record);
      })
      /*遍歷所有*/
      mpArray.forEachItem(record => {
        // console.log(record);
      })
    }
  }

  constructor(private kvDiffers: KeyValueDiffers) {
  }

  ngOnInit(): void {
    if (this.sex) {
      this.differs = this.kvDiffers.find(this.sex).create()
    }
  }

}

IterableDiffer

跟蹤隨時間變化為可迭代的策略。用於通過NgForOf影響DOM中的等效更改來響應可迭代的更改

在檢視IterableDiffer 原始碼的時候我們會發現很多部分跟KeyValueDiffers 有重疊性,

內部NgForOf使用了生命週期掛鉤ngOnChangesngDoCheckngOnChanges該指令用於使用集合find例項的方法根據當前集合的型別選擇一個差異IterableDiffersngDoCheck用於將差值應用於集合的當前值。在不同的是要收集與以前的值進行比較,並返回更改列表

有趣的是,差異如何比較集合中的各個值。特別是,它使用值的哪些屬性來區分它們。為此,我們需要看一下TrackByFunction介面

程式碼

export interface TrackByFunction<T> {
  (index: number, item: T): any;
}

demo

<div *ngFor="let item of sex;trackBy:indexFn" >{{item}}</div>

sex=['a','b','c']
indexFn(index,item){
    console.log(index,item);
    return index
  }

0 "a"
1 "b"
2 "c"

不同點

iterableDiffer 比較專案序列

KeyValueDiffer 比較字典

相關文章