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

时间:2019-01-18 10:53:23

标签: angular

我有2个嵌套组件。一个是父级( AppComponent ),另一个是子级( TooltipComponent )。两个组件都使用OnPush更改检测。现在,无论何时更改父组件的代码,我都想更新子组件视图。我正在传递对孩子输入的新引用,但它不会更新视图。

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

  1. 如果我未在计时器中调用输入的更改代码,则按钮Click事件会触发子视图更新
  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');
  }

}

2 个答案:

答案 0 :(得分:0)

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

如果您只有一个简单的属性,最好将其直接用作输入(例如,只有时间而不是包含时间的对象)。

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

看看here。尤其是“了解可变性”部分。

更新

我做了一个Stackblitz来告诉你,我的意思。如果您为输入创建新对象,则无需调用changeDetection本身。

Stackblitz

答案 1 :(得分:0)

@ R.Richards是正确的-OnPush中不应包含AppComponent,因为这是应用程序的根组件,更改检测需要从某个地方开始,而AppComponent是其中的地方它发生了。为了使您的测试更具可测量性,您应该使用AppComponentParentComponentChildComponent-AppComponent以外的所有元素,并且ChangeDetection设置为OnPush

此代码:

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

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

如果要使其工作,则需要在更新AppComponent类中的this.childInput = { time: new Date() this.cd.detectChanges() }; 之后添加一行,以便其模板将获得新的绑定,然后将其传递给子代组件。

{{1}}