OnPush 更改检测不适用于子组件输入中的新引用



我有 2 个嵌套组件。一个是父项(AppComponent),第二个是子项(工具提示组件)。这两个组件都使用OnPush更改检测。现在,每当子组件的输入从父代码更改时,我都会更新子组件视图。我正在传递对孩子输入的新引用,但它不会更新视图。

我可以通过执行以下操作来更新子视图:

  1. 如果我没有在计时器中调用输入更改代码,按钮 单击事件触发子视图更新
  2. 如果我在单击时手动调用detectchanges()markforcheck(),则子视图将更新。

根据 OnPush 文档,我应该能够通过将新引用传递给其输入变量来更新子视图。如果我在这里遗漏了什么,请告诉我。

import { Component, OnChanges, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { timer } from 'rxjs';
@Component({
  selector: 'app-root',
  template: `
    <tooltip [input]="childInput"></tooltip>
    <button (click)="onClick()" >Trigger change detection</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements OnChanges  {
  constructor(private cd: ChangeDetectorRef){  }
  childInput = {
    time: new Date()
  };
  ngOnChanges() {
    console.log('App component on changes.');
  }
  onClick() {  
    timer(1000).subscribe(sub => {       

      this.childInput = {
        time: new Date()
      };  
    });  
  }
}

import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChange, SimpleChanges, Output, ChangeDetectorRef } from '@angular/core';
@Component({
  selector: 'tooltip',
  template: `
    <h1>{{input.time}}</h1>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class TooltipComponent implements OnChanges  {
  constructor(private cd: ChangeDetectorRef,)  {}
  @Input() input;
  ngOnChanges(){
    console.log('tooltip on changes called');
  }
}

@R.Richards 是对的 - 您不应该在AppComponent中使用OnPush,因为这是应用程序的根组件,更改检测需要从某个地方开始,AppComponent就是它发生的地方。为了使您的测试更具可测量性,您应该具有 AppComponentParentComponentChildComponent - 除ChangeDetection设置为 OnPushAppComponent 之外的所有测试。

此代码:

this.childInput = {
  time: new Date()
};  

更新 AppComponent 类中的childInput,但不更新其模板中的,因此您永远不会更新子组件@Input()

如果要使其正常工作,则需要在更新类中的childInput后添加一行AppComponent以便其模板将获取新绑定,然后将其传递给子组件。

this.childInput = {
  time: new Date()
  this.cd.detectChanges()
};  

不会触发更改检测,因为只有输入对象中的值发生了更改,而不是对象本身。

如果你只有一个简单的属性,最好直接使用它作为输入(例如,只有时间而不是一个包裹时间的对象)。

如果你有一个对象,并且只需要更改一个属性,你可以使用 Object.assign({}, NEW_OBJ),其中NEW_OBJ是你修改的对象,设置了新的时间。这样,您可以确保对象引用更改并触发更改检测。

看看这里。尤其是"理解可变性"部分。

更新

做了一个堆栈闪电战给你展示,我的意思。如果您为输入创建新对象,则无需调用 changeDetection 本身。

斯塔克闪电战

最新更新