我有 2 个嵌套组件。一个是父项(AppComponent),第二个是子项(工具提示组件)。这两个组件都使用OnPush
更改检测。现在,每当子组件的输入从父代码更改时,我都会更新子组件视图。我正在传递对孩子输入的新引用,但它不会更新视图。
我可以通过执行以下操作来更新子视图:
- 如果我没有在计时器中调用输入更改代码,按钮 单击事件触发子视图更新
- 如果我在单击时手动调用
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
就是它发生的地方。为了使您的测试更具可测量性,您应该具有 AppComponent
、 ParentComponent
和 ChildComponent
- 除ChangeDetection
设置为 OnPush
的 AppComponent
之外的所有测试。
此代码:
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 本身。
斯塔克闪电战