我不明白为什么即使我使用ChangeDetectionStrategy.OnPush和changeDetectorRef.detach()调用了函数ngDoCheck。 我的应用程序中有数千个组件,如果从child2引发了一个事件(鼠标点击等),我想阻止child1的changeDetection。
这是plunker
如你所见,我有一个父组件
@Component({
selector: 'my-app',
template: `
<app-child1 test="test"></app-child1>
<app-child2 test="test"></app-child2> `,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
test = 'test';
constructor() { }
ngDoCheck() {
console.log("### ngDoCheck app component");
}
}
和2个相同的孩子:
@Component({
selector: 'app-child1',
template: `<input type="text" [(ngModel)]="test" /><br/> `,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class Child1Component implements OnInit {
@Input()
test: string;
constructor(public cd: ChangeDetectorRef) { }
ngAfterViewInit() {
console.log("###### DETACH child 1");
this.cd.detach();
}
ngDoCheck() {
console.log("### ngDoCheck child 1");
}
}
如果我开始输入child1的输入,则会调用child2的ngDoCheck函数。
想想有成千上万的孩子,它真的很慢......
谢谢!
答案 0 :(得分:3)
这是预期的行为,请阅读Everything you need to know about change detection in Angular。这是引用:
- 在子组件上调用OnInit和ngDoCheck(仅在首次检查时调用OnInit)
- 运行子视图的更改检测(重复此列表中的步骤)
醇>
因此,您可以看到始终在子组件上触发ngDoCheck
。在尝试运行子组件的更改检测时,在后执行OnPush
检查。这是引用:
最后,对当前视图的更改检测负责 开始对子视图进行更改检测(操作8)。这是 选中子组件视图状态的位置以及是否为 ChecksEnabled,然后对于此视图执行更改检测。 以下是相关代码:
viewState = view.state;
...
case ViewAction.CheckAndUpdate:
if ((viewState & ViewState.ChecksEnabled) &&
(viewState & (ViewState.Errored | ViewState.Destroyed)) === 0) {
checkAndUpdateView(view);
}
}
但是,只会针对使用OnPush
策略的顶级组件调用它。它不会在子组件上调用:
normal component
|
child OnPush component <---- ngDoCheck called only for this component
|
child component 1 <---- ngDoCheck is not called for this component
|
child component 2 <---- ngDoCheck is not called for this component
它被触发为您提供在此挂钩内执行自己的自定义逻辑的机会,并且选择以便即使@Input
具有class OnPushComponent {
constructor(private cd: ChangeDetectorRef) {}
ngDoCheck() {
if (some check) {
this.cd.markForCheck();
}
}
}
的避风港,也可以运行更改检测周期改变:
class RestaurantDetailSerializer(serializers.ModelSerializer):
category = CategorySerializer()
weather = WeatherSerializer()
distance = DistanceSerializer()
images = ImageSerializer(many=True, read_only=True)
ratingAverage = serializers.SerializerMethodField(read_only=True)
def get_ratingAverage(self, restaurant):
ratingAvgVal = Star.objects.filter(
restaurant=restaurant
).aggregate(Avg('rating'))['rating__avg']
return ratingAvgVal if ratingAvgVal is not None else 0
class Meta:
model = Restaurant
fields = ('id', 'name', 'address', 'category', 'weather',
'distance', 'description', 'images', 'ratingAverage', )
另请参阅Angular ngDoCheck() gets called even with ChangeDetectionStrategy.OnPush这个答案,了解实际用例示例。