如何使用ChangeDetectionStrategy进行父子组件之间的数据更新

问题描述

我看了几个与ChangeDetectionStrategy相关的主题,我对它的不同用法感到困惑。我只是想在父组件上更改数据时更新子组件中的数据。为此,我看到changeDetection: ChangeDetectionStrategy.OnPush添加到父级的Component字段中,但是我不确定是否应该使用ChangeDetectorRef参数或某些方法,例如ngDoCheck()方法。那么,如何在父子组件之间执行此操作?我应该显式添加来自父级的参数,还是会自动更新@Input变量?

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

@Component({
  selector: 'app-child',templateUrl: './child.component.html',changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
  @input() data: string[];

  constructor(private cd: ChangeDetectorRef) {}

  refresh() {
    this.cd.detectChanges();
  }
}

解决方法

ChangeDetectionStrategy.OnPush的不同之处在于,只有在发生以下类似情况时,您的组件才会检测到更改:

  1. 输入参考更改
  2. 一个事件源自该组件或其子组件
  3. 在视图中使用异步管道
  4. 明确运行更改检测

因此,如果您不更改输入的引用,则必须手动检测更改。 这是stackblitz,显示了OnPushDefault

之间的区别 ,

使用 ChangeDetectionStrategy.OnPush ,您的子组件仅在 @Input 中的数据确实更新时才执行更新,因此您需要数据不可变,那些在更新了Angular数据后将执行ChangeDetector并更新组件视图。

您可以检查以下示例:https://angular-cd-immutable-example.stackblitz.io

,

一种方法是使用slice方法创建对数组的新引用。

A full stackblitz example can be seen here.

app.component.html

<button 
     (click)="people.push({firstName: '1',lastName: '1'}); people = people.slice()">
   +</button>
<div>
  <p> {{ people | json }} </p>
</div>
<br/>
<person [persons]="people"></person>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',templateUrl: './app.component.html',styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
   people: any[] = [ 
     {
      firstName: "Alex1",lastName: "Brown1",age: 55,},{
      firstName: "Foo2",lastName: "Bar2",age: 44,{
      firstName: "Fido3",lastName: "Johnson3",age: 14,}

   ]
}

person.component.html

<div *ngFor="let person of persons">
  Hello I am {{person.firstName}} and I am {{ person.age}}
</div>

和person.component.ts

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

class test {}
@Component({
  selector: 'person',templateUrl: './person.component.html',styleUrls: ['./person.component.css'],changeDetection: ChangeDetectionStrategy.OnPush
})
export class PersonComponent implements OnInit {
  @Input() persons: any;
  
}