简体   繁体   English

Angular 2中的ChangeDetectionStrategy.OnPush和Observable.subscribe

[英]ChangeDetectionStrategy.OnPush and Observable.subscribe in Angular 2

I'm trying to wrap my head around best practice when using Observables alongside ChangeDetectionStrategy.OnPush . 在使用Observables和ChangeDetectionStrategy.OnPush时,我正试图围绕最佳实践。

The example demonstrates the common scenario of wanting to show some kind of loading message (or a simple spinner animation perhaps): 该示例演示了想要显示某种加载消息(或者可能是简单的微调器动画)的常见场景:

Plnkr here Plnkr在这里

@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!';
        }

      });

  }
}

I more or less understand the requirement for immutability with OnPush and, to me at least, it currently makes sense when talking about actual model data (likely held in some kind of store). 我或多或少了解OnPush对不变性的要求,至少对我而言,当谈到实际的模型数据(可能存在于某种商店中)时,它目前是有意义的。

So, I have two questions: 所以,我有两个问题:

  1. Why doesn't the assignment of the new string value 'Success!' 为什么不分配新的字符串值'Success!' trigger the change detector? 触发变化检测器? As far as immutability is concerned, the value has changed, right? 就不变性而言,价值已发生变化,对吧?
  2. How should lightweight internal component state (ie. loadingMessage ) be implemented when using ChangeDetectionStrategy.OnPush ? 使用ChangeDetectionStrategy.OnPush时,应如何实现轻量级内部组件状态(即loadingMessage )? If there are multiple best practices, please point me in the right direction. 如果有多种最佳实践,请指出正确的方向。

Good question. 好问题。 I have two quotes from Savkin about onPush (since the Angular.io docs don't seem to have any info on this topic yet): 我有两个来自Savkin的关于onPush (因为Angular.io文档似乎没有关于这个主题的任何信息):

The framework will check OnPush components only when their inputs change or components' templates emit events. 只有在输入更改或组件模板发出事件时,框架才会检查OnPush组件。 -- ref - 参考

When using OnPush , Angular will only check the component when any of its input properties changes, when it fires an event, or when an observable fires an event. 使用OnPush ,Angular仅在任何输入属性更改时,触发事件时或者当observable触发事件时检查组件。 -- ref (in a comment reply to @vivainio) - 参考 (回复@vivainio)

The second quote seems more complete. 第二个引用似乎更完整。 (Too bad it was buried in a comment!) (太糟糕了,它被埋没在评论中!)

Why doesn't the assignment of the new string value Success! 为什么不分配新的字符串值Success! trigger the change detector? 触发变化检测器? As far as immutability is concerned, the value has changed, right? 就不变性而言,价值已发生变化,对吧?

OnPush immutability is in reference to input properties, not normal instance properties. OnPush不变性是指输入属性,而不是普通实例属性。 If loadingMessage were an input property and the value changed, change detection would execute on the component. 如果loadingMessage是输入属性并且值已更改,则将在组件上执行更改检测。 (See @Vlado's answer for Plunker.) (参见@Vlado对Plunker的回答。)

How should lightweight internal component state (ie, loadingMessage ) be implemented when using ChangeDetectionStrategy.OnPush ? 使用ChangeDetectionStrategy.OnPush时,应如何实现轻量级内部组件状态(即loadingMessage )? If there are multiple best practices, please point me in the right direction. 如果有多种最佳实践,请指出正确的方向。

Here's what I know so far: 这是我目前所知道的:

  • If we change the internal state as part of handling an event, or part of an observable firing, change detection executes on the OnPush component (ie, the view will update). 如果我们将内部状态更改为处理事件或可观察触发的一部分,则更改检测将在OnPush组件上执行(即视图将更新)。 In your particular case, I was surprised that the view did not update. 在您的特定情况下,我很惊讶该视图没有更新。 Here are two guesses as to why not: 这里有两个猜测,为什么不:
    • Adding delay() makes Angular look at it more like a setTimeout() rather than an observable change. 添加delay()使Angular更像是setTimeout()而不是可观察的更改。 setTimeout s do not result in change detection execution on an OnPush component. setTimeout不会导致OnPush组件上的更改检测执行。 In your example the Change Detector has completed its work 2 seconds before the value of loadingMessage is changed. 在您的示例中,更改检测器已在loadingMessage的值更改之前2秒完成其工作。
    • Like @Sasxa shows in his answer, you have to have a binding in the template to the Observable . 就像@Sasxa在他的回答中所示,你必须在模板中有一个绑定到Observable Ie, maybe it is more than just "an observable fires"... maybe it has to be a bound observable that fires. 即,也许这不仅仅是更多的“可观察到的火灾。” ...也许这已经是一个必然观察到的是火灾。 In which case, creating loadingMessage (or even a more generic state property) as an Observable itself will allow you to bind your template to its value (or multiple async values), see this example plnkr . 在这种情况下,创建loadingMessage (甚至更通用的state属性)作为Observable本身将允许您将模板绑定到其值(或多个异步值),请参阅此示例plnkr
      Update 2016-04-28: it appears the binding must include | async 更新2016-04-28:看来绑定必须包括| async | async , as shown in the plnkr, and in this plnkr . | async ,如plnkr和此plnkr中所示
  • If we change the internal state and it is not part of event handling or an observable firing, we can inject ChangeDetectorRef into our component and call method markForCheck() to cause change detection to execute on the OnPush component and all ancestor components up to the root component. 如果我们改变内部状态,它不是事件处理或可观察到发射的一部分,我们可以注入ChangeDetectorRef到我们的组件和调用方法markForCheck()引起的变化探测到上执行OnPush组件和所有祖先组件升级到根零件。 If only view state is changed (ie, state that is local to the component and maybe its descendants), detectChanges() can be used instead, which will not mark all ancestor components for change detection. 如果仅更改了视图状态(即,组件本地的状态以及可能是其后代的状态),则可以使用detectChanges() ,而不会标记所有用于更改检测的祖先组件。 Plunker Plunker

AFAIK, OnPush is used when working directly with observables : 直接使用observable时使用AFAIK, OnPush

//our root app component
import {Component, OnInit, ChangeDetectionStrategy} from 'angular2/core'
import {Observable} from 'rxjs/Observable';
import 'rxjs/Rx';

@Component({
  selector: 'my-app',
  template: `Are we loading?: {{ loadingMessage |async }}`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class App implements OnInit {
  private loadingMessage;
  constructor() { }

  ngOnInit() {
    this.loadingMessage = Observable.of(true)
      .delay(2000)
  }
}

With this ChangeDetectionStrategy.OnPush you are telling your component to only listen for changes on it's input properties. 使用此ChangeDetectionStrategy.OnPush您告诉您的组件仅侦听其输入属性的更改。

I added loading component to your example just to show you how it works: http://plnkr.co/edit/k5tkmcLlzkwz4t5ifqFD?p=preview 我在您的示例中添加了加载组件,以向您展示它是如何工作的: http//plnkr.co/edit/k5tkmcLlzkwz4t5ifqFD?p = preview

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ChangeDetectionStrategy.OnPush 和数据不变性问题 - ChangeDetectionStrategy.OnPush and data immutability issue angular2中的`changeDetection:ChangeDetectionStrategy.OnPush`是否仅在一个方向上起作用:top-> bottom? - Does `changeDetection: ChangeDetectionStrategy.OnPush` in angular2 only works in one direction: top->bottom? 角度:Observable.subscribe取消同步怪异错误 - Angular: Observable.subscribe desync weird error ChangeDetectionStrategy.OnPush何时实际运行变更检测? - When does ChangeDetectionStrategy.OnPush Actually Run Change Detection? 当组件被标记为 ChangeDetectionStrategy.OnPush 时,单元测试失败 - unit test fails when the component is marked as ChangeDetectionStrategy.OnPush Observable.subscribe() 在 IE 中无法处理 Angular 7 中的组件更改 - Observable.subscribe() not working in IE on component change in Angular 7 从通用文件中调用angular Observable.subscribe() - Calling angular Observable.subscribe() from common file 为什么 changeDetectionStrategy.OnPush 在@Input 属性更改时不更新但更新@Output 会触发属性更改? - Why changeDetectionStrategy.OnPush does not update in @Input attribute change but does update @Output trigger attribute change? 将Observable.subscribe()返回的值赋给const - Assign value returned by Observable.subscribe() to a const RxJs:如何关闭嵌套 observable.subscribe 调用的订阅 - RxJs : How to close subscription of nested observable.subscribe call
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM