简体   繁体   English

从Observable的订阅中获取更新的值

[英]Getting updated values from Observable's subscription

I have noticed something about Observables in Angular 2 that I cannot explain and hope a good sould sheds light on me. 我注意到有关Angular 2中Observables的一些内容,我无法解释,并希望一个好的模型可以揭示我。

My understanding was that when subscribing to an Observable you have basically two strategies to consume the value it emits: 我的理解是,在订阅Observable时,你基本上有两种策略来消耗它发出的值:

stream combined with async pipe, as in: 流与异步管道相结合,如:

myTextSubscription$ = SomeObservable.subscribe();

{{ myTextSubscription$ | async }}

or extract the value and bind it from within the subscribe handler: 或者从订阅处理程序中提取值并绑定它:

myTextSubscription$ = SomeObservable.subscribe(text => this.text = text);

{{ text }}

Well, the problem is that I have already tried a couple of times to use the latter approach and I never managed to get the text value updated, unless I invoke this.cdRef.markForCheck() within the handler. 好吧,问题是我已经尝试了几次使用后一种方法,我从来没有设法更新text值,除非我在处理程序中调用this.cdRef.markForCheck() I guess invoking the changeDetection manually should not be required for such a basic scenario - at least I haven't seen that used in any of screencasts or tutorials. 我想这种基本场景不应该需要手动调用changeDetection - 至少我没有看到在任何截屏视频或教程中使用过。

Does this sound familiar to anyone? 这听起来对任何人都很熟悉吗? Is it my wrong understanding of the method, or is it perhaps a bug in Angular 2? 这是我对该方法的错误理解,还是Angular 2中的错误?


Edit: 编辑:

The code above has been abstracted as I believed the problem could be explained on a more abstract level. 上面的代码已被抽象,因为我认为问题可以在更抽象的层面上解释。

I cannot recall the first case when it bit me, but now the Observable comes from ngrx store, so it's basically something along these lines: 我不记得第一个案例,当它咬我,但现在Observable来自ngrx商店,所以它基本上是这样的:

this.text$ = store.let((state$: Observable<State>) => {
  return state$.select(state => state.text);
});

This usually happens if SomeObservable is somehow initialized outside Angulars zone or uses some API that is not coverted by zone.js. 如果SomeObservable以某种方式在Angulars区域之外初始化或使用某些未被zone.js转换的API,则通常会发生这种情况。

We would need to see how SomeObservable is exactly constructed to know for sure. 我们需要看看SomeObservable是如何精确构建的,以确定无疑。

In fact, you shouldn't subscribe to the observable when using async . 实际上,在使用async时不应订阅observable。 It's why async is that awesome. 这就是为什么async是那么棒的原因。 It handles both subscribe AND unsubscribe when your component is initialized/destroyed. 它在初始化/销毁组件时处理subscribeunsubscribe

So instead of : 所以代替:
JS JS

myTextSubscription$ = SomeObservable.subscribe();

HTML HTML

{{ myTextSubscription$ | async }}

You should rather have : 你应该宁愿:
JS JS

myTextSubscription$ = SomeObservable;

HTML HTML

{{ myTextSubscription$ | async }}

I'd like to clarify the use of $ in your variable name : 我想澄清变量名中$的使用:
- an observable should be suffixed with '$' - 观察值应以“$”为后缀
- when you use subscribe, you do not get an observable - 当你使用订阅时,你没有得到可观察的

With respect of convention : 关于惯例:
JS JS

let someObservable$ = ...;

HTML HTML

{{ someObservable$ | async }}

Remember that : 请记住:
- you need to unsubscribe manually from an observable when you use subscribe to it, except from the router and http) - 当您使用订阅时,您需要从observable 手动取消订阅,但路由器和http除外)
- when you have a .subscribe , the value returned is of type Subscription (which means you can unsubscribe from it) - 当你有.subscribe ,返回的值是Subscription类型(这意味着你可以取消订阅)

So here's an overview of a cleaner structure (without using async pipe) : 所以这里是一个更清洁的结构的概述(不使用异步管道):

@Component({
  selector: '...',
  templateUrl: '...html',
  styleUrls: ['...css']
})
export class AppComponent implements OnInit, OnDestroy {
    private myText: string;
    private myTextSubscription: Subscription;

    constructor() { }

    ngOnInit() {
        // I assume here that you declared an observable called "someObservable"

        this.myTextSubscription = someObservable$.subscribe(text => this.myText = text);
    }

    ngOnDestroy() {
        // as our observable is not coming from router or http, we need to manually
        // unsubscribe in order to avoid memory leaks

        this.myTextSubscription.unsubscribe();
    }

}

EDIT 1: With your updated example, here's how you should use it with @ngrx : 编辑1:使用您更新的示例,以下是如何将它与@ngrx一起使用:

@Component({
  selector: '...',
  templateUrl: '...html',
  styleUrls: ['...css']
})
export class AppComponent implements OnInit, OnDestroy {
  private text: string;
  private textSub: Subscription;

  constructor(private store$: Store<State>) {
    this.textSub =
        store$.select('yourState')
            .subscribe((state: State) => this.text = state);
  }

  ngOnDestroy() {
    this.textSub.unsubscribe();
  }
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM