首页 文章

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

提问于
浏览
6

我不明白为什么即使我使用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" />
`, 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 回答

  • 3

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

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

    因此,您可以看到始终在子组件上触发 ngDoCheck . 尝试运行子组件的更改检测时, OnPush 检查执行 after . 这是引用:

    最后,当前视图的更改检测负责启动子视图的更改检测(操作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
    

    为什么会触发?

    它被触发,让你有机会在这个钩子内执行你自己的自定义逻辑,并且 choose 即使 @Input 没有改变也运行一次更改检测周期:

    class OnPushComponent {
       constructor(private cd: ChangeDetectorRef) {}
    
       ngDoCheck() {
          if (some check) {
              this.cd.markForCheck();
          }
       }
    }
    

    另请参阅Angular ngDoCheck() gets called even with ChangeDetectionStrategy.OnPush这个答案的真实用例示例 .

相关问题