ChangeDetectionStrategy.OnPush一起使用Observables时,我想尽全力以赴。

该示例演示了想要显示某种加载消息(或者可能是简单的微调器动画)的常见情况:

Plnkr here

@Component({
  selector: 'my-app',
  template: `Are we loading?: {{loadingMessage}}`,

  // Obviously "Default" will notice the change in `loadingMessage`...
  // changeDetection: ChangeDetectionStrategy.Default

  // But what is best practice when using OnPush?
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class App implements OnInit {

  private loadingMessage = "Wait for it...";

  constructor() {

  }

  ngOnInit() {

    // Pretend we're loading data from a service.
    // This component is only interested in the call's success
    Observable.of(true)
      .delay(2000)
      .subscribe(success => {

        if(success){
          console.log('Pretend loading: success!');

          // OnPush won't detect this change
          this.loadingMessage = 'Success!';
        }

      });

  }
}

我或多或少了解了OnPush的不可变性的要求,至少在我看来,谈论实际模型数据(可能保存在某种类型的商店中)目前是有意义的。

因此,我有两个问题:
  • 为什么分配新的字符串值'Success!'不会触发更改检测器?就不变性而言,值(value)已经改变,对吗?
  • 使用loadingMessage时应如何实现轻量级内部组件状态(即ChangeDetectionStrategy.OnPush)?如果有多种最佳做法,请指出正确的方向。
  • 最佳答案

    好问题。我从Savkin收到两个关于onPush的引号(因为Angular.io文档似乎还没有关于此主题的任何信息):



    第二个报价似乎更完整。 (太糟糕了,它被埋在了评论中!)


    OnPush不变性是指输入属性,而不是普通实例属性。如果loadingMessage是输入属性,并且值已更改,则将在组件上执行更改检测。 (请参阅@Vlado对Plunker的回答。)



    到目前为止,这是我所知道的:

  • 如果我们在处理事件或观察到触发时更改了内部状态,则更改检测将在OnPush组件上执行(即, View 将更新)。在您的特定情况下,我对该 View 没有更新感到惊讶。关于为何不这样做,有两个猜测:
  • 添加delay()使Angular看起来更像是setTimeout(),而不是可观察的更改。 setTimeout不会导致对OnPush组件执行更改检测。在您的示例中,更改检测器在loadingMessage的值更改前2秒钟完成了工作。
  • 就像@Sasxa在他的答案中所示,您必须在模板中绑定(bind)Observable。也就是说,也许不仅仅是“可观察到的火灾” ...可能还必须是绑定(bind)的可观察到的火灾。在这种情况下,创建loadingMessage(或什至是更通用的state属性)作为Observable本身将使您可以将模板绑定(bind)到其值(或多个异步值),请参阅this example plnkr更新2016-04-28:,绑定(bind)似乎必须包含| async,如plnkr和this plnkr所示。
  • 如果我们更改内部状态,并且它不是事件处理或可观察的触发的一部分,则可以将ChangeDetectorRef注入(inject)到我们的组件中,并调用markForCheck()方法以使更改检测在OnPush组件和所有祖先组件上执行,直到根组件为止。如果仅更改 View 状态(即组件及其后代的本地状态),则可以使用detectChanges()代替,它不会标记所有祖先组件以进行更改检测。 Plunker
  • 09-18 03:37