开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
示例四
markForCheck和detectChanges的区别是什么呢?
- detectChanges, 它会触发当前组件和子组件的变化检测;
- markForCheck, 它不会触发变更检测,但是会把当前的OnPush组件和所有的父组件为OnPush的组件 标记为需要检测状态,在当前或者下一个变化检测周期进行检测;
@Component({
selector: 'app',
styleUrls: ['./app.component.scss'],
template: `
<h1>{{count}}</h1>
<button (click)="normalClick()">Click</button>
<main [options]="options" [actionSubject$]="actionSubject$"></main>`
})
export class AppComponent {
options: any = { name: 'Tom' };
count: number = 0;
normalClick(): void {
this.count++;
this.actionSubject$.next(this.count);
}
}
@Component({
selector: 'main',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h1>{{count}}</h1>
`
})
export class MainComponent {
@Input() options: any;
@Input() actionSubject$!: Subject<any>;
count: number = 0;
constructor(private ref: ChangeDetectorRef){}
ngOnInit(){
this.actionSubject$.subscribe((d: any) => {
this.count = d;
if (this.count >= 3 && this.count <= 6) {
this.ref.markForCheck();
this.count += 100;
}
});
}
}
上面的代码,当App组件中Button点击三次后,Main组件中显示的是多少呢?
显示的是103,因为markForCheck() 会把当前组件和父组件都标记为需要check,也就是当到变更检测时,会执行变更检测。标记完后,变更检测并没有发生,紧接着count的值加100,那就是103。当异步任务执行完成后,进行变更检测时,发现OnPush被标记为需要检测,那执行完变更检测后,页面上会显示103。
...
export class MainComponent {
...
constructor(private ref: ChangeDetectorRef){}
ngOnInit(){
this.actionSubject$.subscribe((d: any) => {
this.count = d;
if (this.count >= 3 && this.count <= 6) {
this.ref.detectChanges();
this.count += 100;
}
});
}
}
上面代码中,当count值等于3后,detectChanges() 会理解执行一次变更检测,所以页面上的值显示为3,紧接着,count值加100,count的值等于103,。等到变更检测时,发现是OnPush,则跳过变更检测。
...
export class MainComponent {
...
constructor(private ref: ChangeDetectorRef){}
ngOnInit(){
this.actionSubject$.subscribe((d: any) => {
this.count = d;
if (this.count >= 3 && this.count <= 6) {
// this.ref.markForCheck();
this.ref.detectChanges();
}
});
}
}
上面代码并不会有任何区别。
需要注意的是,可能会在ngDoCheck中改变count的值。
...
export class MainComponent {
...
constructor(private ref: ChangeDetectorRef){}
ngOnInit(){
this.actionSubject$.subscribe((d: any) => {
this.count += d;
if (this.count >= 3 && this.count <= 6) {
// this.ref.markForCheck();
this.ref.detectChanges();
}
});
}
ngDoCheck(){
this.count++;
}
}
这个自己思考一下具体的结果吧。
一个是4,一个是3。
示例五
@Component({
selector: 'main',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h1>{{count}}</h1>
`
})
export class MainComponent {
count: number = 0;
constructor(private ref: ChangeDetectorRef){}
ngOnInit(){
...
}
ngAfterViewInit(): void {
this.count++;
}
}
上面代码,如果是OnPush策略的话,页面加载完成后,显示多少?如果是Default策略的话,显示多少呢?这些差异,其实都是和变更检测策略有关系的。
在OnPush下,并不会报错,而且页面上显示的0。
@Component({
selector: 'main',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h1>{{count}}</h1>
`
})
export class MainComponent {
count: number = 0;
constructor(private ref: ChangeDetectorRef){}
ngOnInit(){
...
}
ngAfterViewInit(): void {
this.count++;
this.ref.checkNoChanges();
}
}
需要注意的是,tick()方法里的view.checkNoChanges() 并没有起作用,所以没有报错。但是,上面代码中使用了组件变更检测器中的checkNoChanges(), 它是起作用的。所以,控制台会报错。所以,方法名一样,但是功能是有区别的。
看了这些例子后,是不是对OnPush策略理解更加深刻了呢。