儿童之间的角度4分离变化检测

时间:2017-08-10 13:59:14

标签: angular angular2-changedetection

我不明白为什么即使我使用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函数。

想想有成千上万的孩子,它真的很慢......

谢谢!

1 个答案:

答案 0 :(得分:3)

这是预期的行为,请阅读Everything you need to know about change detection in Angular。这是引用:

  
      
  1. 在子组件上调用OnInit和ngDoCheck(仅在首次检查时调用OnInit)
  2.   
  3. 运行子视图的更改检测(重复此列表中的步骤)
  4.   

因此,您可以看到始终在子组件上触发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这个答案,了解实际用例示例。