未调用 ngOnChanges 但视图已正确更新

ngOnChanges is not called but the view is updated correctly

我有一个与以下代码相关的问题:

Child

export class ChildComponent implements OnChanges {
    public @Input() data: string[];

    ngOnChanges(changes: SimpleChanges) {
        console.log('I am here');
    }
}

Child 模板

{{ data | json }} // This is not necessary. The behaviour is the same with or without it.

<div *ngFor="let item of data">
    {{ item }}
</div>

Parent

export class AppComponent implements OnInit {
    public test: string[] = ['hello'];

    ngOnInit() {
        console.log('I am here');
    }

    public addItem() {
        this.test.push('sample');
    }
}

Parent 模板

<child-component [data]="test"></child-component>
<button (click)="addItem()">Add</button>

我知道 ngOnChanges 只会在数组引用更改时调用,如果我将元素推送到数组,则不会调用它。以下内容引起了我的注意。当我按下添加按钮时,一个新元素被添加到数组中并且视图被正确更新。我使用 json 管道和 ngFor 来证明它更新正确。如果我不使用 json 管道,行为是相同的。那么,如果视图更新正确,为什么不调用 ngOnChanges?谁负责检测是否有变化显示在视图中?

综上所述,疑点如下。为什么当一个元素被添加到数组时视图被正确更新但为什么 ngOnChanges 没有被调用?

变化检测的方式不同?

您可能很清楚 ngOnChanges 是为处理 @Input() 属性中的任何更改而设计的(以防将新数据简单地馈送到组件可能会产生一些额外的影响并且不能通过组合 set@Input() 来完成)。所以它只关注 @Input() 变化。另外,如您所知,仅当引用即将更改时才会更新。

并且您的组件无论如何都会更新,因为:

  • 您并没有告诉组件仅使用 OnPush 更改检测策略(因此它不仅会更改任何 @Input() 或任何 observable/event 的引用更改)
  • 此外(这是这里的关键)您的子视图中有一个 inpure 管道。在这里我发现了一些关于脏管道的问题,我认为它应该回答你的问题: (as json pipe is inpure - docs)。尝试删除它,看看会发生什么。

请接受这只是一个理论的事实。但我很确定这是正确的。

编辑:哦,官方文档中似乎有一个完美的例子 here:

...the flying heroes display updates as you add heroes, even when you mutate the heroes array.