Comment obtenir la valeur actuelle de RxJS sujet ou Observable?

j'ai Angulaire 2 service:

import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject}    from 'rxjs/Subject';

@Injectable()
export class SessionStorage extends Storage {
  private _isLoggedInSource = new Subject<boolean>();
  isLoggedIn = this._isLoggedInSource.asObservable();
  constructor() {
    super('session');
  }
  setIsLoggedIn(value: boolean) {
    this.setItem('_isLoggedIn', value, () => {
      this._isLoggedInSource.next(value);
    });
  }
}

Tout fonctionne très bien. Mais j'ai un autre composant qui n'a pas besoin de souscrire, il a juste besoin d'obtenir la valeur actuelle d'isLoggedIn à un certain moment dans le temps. Comment puis-je faire cela?

90
demandé sur Baconbeastnz 2016-05-07 17:54:35

5 réponses

Un Subject ou Observable n'ont pas de valeur actuelle. Lorsqu'une valeur est émise, elle est transmise aux abonnés et le Observable en est fait.

si vous voulez avoir une valeur actuelle, utilisez BehaviorSubject qui est conçu pour exactement ce but. BehaviorSubject conserve la dernière valeur émise et l'émet immédiatement aux nouveaux abonnés.

Il a aussi une méthode getValue() pour obtenir la valeur actuelle.

173
répondu Günter Zöchbauer 2016-05-07 14:56:26

La seule façon de devrait obtenir des valeurs "hors de" Observable/Sujet est à vous abonner!

si vous utilisez getValue() vous faites quelque chose d'impératif dans le paradigme déclaratif. Il est là comme une trappe d'évacuation, mais 99,9% du temps, vous ne devriez pas utiliser getValue() . il y a quelques choses intéressantes que getValue() fera: il lancera une erreur si le sujet a été désabonné, il vous empêchera d'obtenir une valeur si le sujet est morte parce qu'elle est erronée, etc. Mais, encore une fois, il est là comme une issue de secours pour des circonstances rares.

il y a plusieurs façons d'obtenir la valeur la plus récente d'un sujet ou Observable d'une manière "Rx-y":

  1. utilisant BehaviorSubject : mais y souscrivant effectivement . Lorsque vous vous abonnez pour la première fois à BehaviorSubject , il envoie de façon synchrone la valeur précédente il reçu ou a été initialisé avec.
  2. utilisant un ReplaySubject(N) : cela cache les valeurs N et les rejoue aux nouveaux abonnés.
  3. A.withLatestFrom(B) : Utilisez cet opérateur pour obtenir la valeur la plus récente de B observable lorsque A émet observable. Vous donnera les deux valeurs dans un tableau [a, b] .
  4. A.combineLatest(B) : Utilisez cet opérateur pour obtenir les valeurs les plus récentes de A et B chaque fois que A ou B émet. Vous donnera les deux valeurs dans un tableau.
  5. shareReplay() : fait une multidiffusion Observable à travers un ReplaySubject , mais vous permet de réessayer l'observable sur erreur. (En gros, cela vous donne ce comportement de mise en cache promise-y).
  6. publishReplay() , publishBehavior(initialValue) , multicast(subject: BehaviorSubject | ReplaySubject) , etc: autres opérateurs qui tirent sur BehaviorSubject et ReplaySubject . Différentes saveurs de la même chose, ils essentiellement multicast la source observable en canalisant toutes les notifications à travers un sujet. Vous devez appeler connect() pour vous abonner à la source avec le sujet.
78
répondu Ben Lesh 2017-07-26 17:17:46

j'ai eu la même situation où les abonnés tardifs s'abonnent au sujet après que sa valeur soit arrivée.

j'ai trouvé ReplaySubject qui est similaire à BehaviorSubject fonctionne comme un charme dans ce cas. Et voici un lien vers une meilleure explication: http://reactivex.io/rxjs/manual/overview.html#replaysubject

4
répondu Kfir Erez 2017-04-13 10:42:28

j'ai rencontré le même problème dans les composants enfants où il fallait d'abord avoir la valeur actuelle du sujet, puis s'abonner au sujet pour écouter les changements. Je maintiens juste la valeur actuelle dans le Service de sorte qu'il est disponible pour les composants d'accès, par exemple:

import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject}    from 'rxjs/Subject';

@Injectable()
export class SessionStorage extends Storage {

  isLoggedIn: boolean;

  private _isLoggedInSource = new Subject<boolean>();
  isLoggedIn = this._isLoggedInSource.asObservable();
  constructor() {
    super('session');
    this.currIsLoggedIn = false;
  }
  setIsLoggedIn(value: boolean) {
    this.setItem('_isLoggedIn', value, () => {
      this._isLoggedInSource.next(value);
    });
    this.isLoggedIn = value;
  }
}

un composant qui a besoin de la valeur actuelle pourrait alors y accéder à partir du service, I. e,:

sessionStorage.isLoggedIn

Je ne sais pas si c'est le bon practice:)

2
répondu Molp Burnbright 2017-11-25 06:01:47

vous pourriez stocker la dernière valeur émise séparément de L'Observable. Puis de le lire en cas de besoin.

let lastValue: number;

const subscription = new Service().start();
subscription
    .subscribe((data) => {
        lastValue = data;
    }
);
-3
répondu Slawa 2018-06-05 11:36:44