Angular 默认的Change detection策略及缺陷

206 阅读1分钟

默认策略下,用户事件,计时器,XHR,promise等事件触发,所有的组件都会执行变更检测。

看一个实际例子:

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'appparentchild',
  template: `<h1>title</h1>
  {{ JerryHelloChange }}
  <child [childContent] = "parentContent"></child>
  `
})
export class ParentChildComponent implements OnInit {

  public parentContent = 'Jerry 222';
  constructor() { }

  get JerryHelloChange(){
    console.log('change in parent view');
    return true;
  }
  ngOnInit(): void {
    this.parentContent = '1';
    let c = setTimeout;
    setTimeout(() => this.parentContent = '2', 3000);
  }

}

@Component({
  selector: 'child',
  template: `<h1>This is child</h1>
  <h2>{{ childContent }}</h2>
  <button (click)="onClick()">Click Me to trigger Change</button> 

  <span>{{ childContent }}</span>`
})
export class ChildComponent{
  
  @Input()
  childContent: string;

  onClick(){
    setTimeout(()=>{ console.log('timeout!')}, 3000);
  }
}

测试结果:

测试发现,即使onClick本身的逻辑不会触发任何Component数据的改变,change detection仍然会不断触发。

如果将changeDetectionStrategy改成push:

import { Component, OnInit, Input, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'appparentchild',
  template: `<h1>title</h1>
  {{ JerryHelloChange }}
  <child [childContent] = "parentContent"></child>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentChildComponent implements OnInit {

  public parentContent = 'Jerry 222';
  constructor() { }

  get JerryHelloChange(){
    console.log('change in parent view');
    return true;
  }
  ngOnInit(): void {
    this.parentContent = '1';
    let c = setTimeout;
    setTimeout(() => {
      this.parentContent = '2';
      console.log('change in parent');
    }, 3000);
  }

}

@Component({
  selector: 'child',
  template: `<h1>This is child</h1>
  <h2>{{ childContent }}</h2>
  <button (click)="onClick()">Click Me to trigger Change</button> 

  <span>{{ childContent }}</span>`
})
export class ChildComponent{
  
  @Input()
  childContent: string;

  onClick(){
    setTimeout(()=>{ console.log('timeout!')}, 3000);
  }
}

则虽然我在ngOnInit里将this.parentContent改成了2,但是页面仍然没有刷新,仍然是1:

需要点一下按钮才能触发页面刷新:

更多Jerry的原创文章,尽在:“汪子熙”: