angular中组件changeDetection为ChangeDetectionStrategy.OnPush时的学习

注:我用的angular 8

一个angular应用是由组件树组成的,changeDetection是其中比较深的部分,我也不懂哈。

angular中changeDetection中的策略有这样的描述:

总而言之,对于一个组件而言,2中changeDetection策略,默认的没啥好说的,主要说一下OnPush的情况。
如果子组件的属性的变化由输入属性决定,那么这个时候就可以启用OnPush这种变更检测策略,这样输入属性不变的时候就不用检测了,省时省力。

1、 输入属性为非对象的时候

index组件:

@Component({
  selector: 'app-index',
  template: '<app-abc [shuru]="shuru"></app-abc>',
})
export class IndexComponent {
  shuru = 1;
  constructor() {
    setInterval(() => {
      this.shuru++;
    }, 1111);
  }
}

abc组件:

@Component({
  selector: 'app-abc',
  template: '  输入是:{{shuru}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})

export class AbcComponent implements OnChanges {
  @Input()
  shuru = 0;
  ngOnChanges(changes: SimpleChanges): void {
    for (let propName in changes) {
      let chng = changes[propName];
      let cur = JSON.stringify(chng.currentValue);
      let prev = JSON.stringify(chng.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}

跑一下看结果:
在这里插入图片描述
这个实在没啥好说的哈!

2、输入属性是一个对象的时候

修改index组件代码如下:

@Component({
  selector: 'app-index',
  template: '<app-abc [shuru]="shuru"></app-abc>',
})
export class IndexComponent {
  shuru = {
    shuru: 1
  };
  constructor() {
    setInterval(() => {
      this.shuru.shuru++;
    }, 1111);
  }
}

修改abc组件如下:

@Component({
  selector: 'app-abc',
  template: '  输入是:{{shuru.shuru}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})

export class AbcComponent implements OnChanges {
  @Input()
  shuru = {shuru: 0};
  ngOnChanges(changes: SimpleChanges): void {
    for (let propName in changes) {
      let chng = changes[propName];
      let cur = JSON.stringify(chng.currentValue);
      let prev = JSON.stringify(chng.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}

再跑一下:
在这里插入图片描述
为什么abc组件里面没变化呢,因为再index组件中输入属性shuru没有变化,我们改变的只是shuru.shuru,angular比较的是shuru的reference

3、输入属性与immutable objects

2没有生效的,是因为我修改的是shuru这个对象,而不是shuru的引用;那么作为输入属性传入的每个对象本身如果是不可修改的,如果我想修改shuru的时候,重新赋值成另外一个对象就可以了。
对于2中的情况,如果我们想让他生效,这么做就好了:
index组件稍微修改下:

      this.shuru = {
        shuru : ++this.shuru.shuru
      };
      // this.shuru.shuru++;

在这里插入图片描述

4、OnPush与事件

除了上述3捕获到变更检测,还有一种诡异的情况:

index组件的代码和2保持一直,修改abc组件的代码如下:

@Component({
 selector: 'app-abc',
 template: ' 输入是:{{shuru.shuru}}  <button (click)="click()">我是按钮</button>',
 changeDetection: ChangeDetectionStrategy.OnPush
})

export class AbcComponent implements OnChanges {
 @Input()
 shuru = {shuru: 0};
 // shuru: Observable<any>;

 ngOnChanges(changes: SimpleChanges): void {
   for (let propName in changes) {
     let chng = changes[propName];
     let cur = JSON.stringify(chng.currentValue);
     let prev = JSON.stringify(chng.previousValue);
     console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
   }
 }
 click() {
   console.log('电力');
 }
}

跑一下:
在这里插入图片描述
对此,我只能解释成,事件的触发,导致组件进行了变更检测;那么,我也可以自己在组件abc中手动做变更检测,所以可以像下面这样做:

5、OnPush与ngDoCheck、ChangeDetectorRef、markForCheck

When should you use ngDoCheck?
Use ngDoCheck when you want to capture changes that Angular otherwise doesn’t.
For example, if a binding references remains unchanged after a click event, ngOnChanges won’t run but ngDoCheck will.

2的基础之上进行。。。
虽然这时候ngOnChanges不执行了,但是ngDoCheck执行啊!!!

修改组件abc的代码如下:

@Component({
  selector: 'app-abc',
  template: '  输入是:{{shuru.shuru}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})


export class AbcComponent implements OnChanges, DoCheck {
  @Input()
  shuru = {shuru: 0};

  constructor(private changeDetectorRef: ChangeDetectorRef,
  ) {
    /*
    Detaches this view from the change-detection tree.
    A detached view is not checked until it is reattached.
    Use in combination with detectChanges() to implement local change detection checks.
    */
    this.changeDetectorRef.detach(); // 如果detach, 那么markForCheck就不起作用了
  }

  ngOnChanges(changes: SimpleChanges): void {
    for (let propName in changes) {
      let chng = changes[propName];
      let cur = JSON.stringify(chng.currentValue);
      let prev = JSON.stringify(chng.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }

  ngDoCheck() {
    console.log('ngDoCheck', this.shuru);
    // this.changeDetectorRef.markForCheck();  // 不detach的时候,这个也可以
    this.changeDetectorRef.detectChanges(); // Checks this view and its children.
  }
}

在这里插入图片描述

6、当输入属性是service时候

居然还能这样!
先搞个服务处理:


@Injectable({
  providedIn: 'root'
})
export class ObsService {
  private messageSource = new BehaviorSubject(1);
  comeOneData = this.messageSource.asObservable();
  changeData(message: any) {
    this.messageSource.next(message);
  }
}

新的index组件如下:

@Component({
  selector: 'app-index',
  template: '<app-abc [shuru]="obs$"></app-abc>',
})
export class IndexComponent {
  shuru = 1;
  constructor(private obs$: ObsService) {
    setInterval(() => {
      this.obs$.changeData(this.shuru++);
    }, 1111);
  }
}

新的abc组件如下:

@Component({
  selector: 'app-abc',
  template: '  输入是:{{shuru["comeOneData"]| async | json}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})

export class AbcComponent implements OnChanges {
  @Input()
  shuru: Observable<any>;
  
  ngOnChanges(changes: SimpleChanges): void {
    for (let propName in changes) {
      let chng = changes[propName];
      let cur = JSON.stringify(chng.currentValue);
      let prev = JSON.stringify(chng.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}

在这里插入图片描述

7、当输入属性是Observable的时候

这个其实和6有点类似的。
index组件是这样的:

@Component({
  selector: 'app-index',
  template: '<app-abc [shuru]="shuru"></app-abc>',
})
export class IndexComponent {
  observer;
  num = 0;
  shuru = Observable.create((observer) => {
    this.observer = observer;
  });

  constructor() {
    setInterval(() => {
      this.observer.next(++this.num);
    }, 1111);
  }
}
7.1 订阅方式

这个方法得多写几行代码。。。在abc组件中subscribe输入的Observable,取出来值之后自己做变更检测插入到模板中:

abc组件如下:

@Component({
  selector: 'app-abc',
  template: '  输入是:{{num}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})


export class AbcComponent implements OnChanges, OnInit {
  @Input()
  shuru: Observable<any>;
  num;

  constructor(private changeDetectorRef: ChangeDetectorRef,
  ) {
  }

  ngOnInit() {
    this.shuru.subscribe((res) => {
      console.log('subscribe',res);
      this.num = res;
      this.changeDetectorRef.detectChanges();
    });
  }

  ngOnChanges(changes: SimpleChanges): void {
    for (let propName in changes) {
      let chng = changes[propName];
      let cur = JSON.stringify(chng.currentValue);
      let prev = JSON.stringify(chng.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}

在这里插入图片描述

7.2 管道

abc组件如下,少些好多代码。不用手动做变更检测了

@Component({
  selector: 'app-abc',
  template: '  输入是:{{shuru|async}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})


export class AbcComponent implements OnChanges {
  @Input()
  shuru: Observable<any>;

  constructor() {}

  ngOnChanges(changes: SimpleChanges): void {
    for (let propName in changes) {
      let chng = changes[propName];
      let cur = JSON.stringify(chng.currentValue);
      let prev = JSON.stringify(chng.previousValue);
      console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }
}

参考文献

https://angular.io/api/core/ChangeDetectorRef

https://vsavkin.com/change-detection-in-angular-2-4f216b855d4c

https://blog.angular-university.io/onpush-change-detection-how-it-works/

https://blog.angularindepth.com/if-you-think-ngdocheck-means-your-component-is-being-checked-read-this-article-36ce63a3f3e5

https://www.stackchief.com/blog/ngDoCheck Example | Angular

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随与博主沟通,第一间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值