318 votes

Comment obtenir la valeur actuelle de RxJS Subject ou Observable?

J'ai un service Angular 2:

 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 s’abonner, il faut juste obtenir la valeur actuelle de isLoggedIn à un moment donné. Comment puis-je faire ceci?

512voto

Günter Zöchbauer Points 21340

Un Subject ou Observable n'a pas de valeur actuelle. Lorsqu'une valeur est émise, elle est transmise aux abonnés et les Observable sont utilisés.

Si vous voulez avoir une valeur actuelle, utilisez BehaviorSubject qui est conçu exactement à cette fin. BehaviorSubject conserve la dernière valeur émise et l’émet immédiatement aux nouveaux abonnés.

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

220voto

Ben Lesh Points 39290

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

Si vous utilisez getValue() vous êtes en train de faire 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 petites choses intéressantes qu' getValue() va faire: Il va lever une erreur si le sujet a déjà été précisé, il va vous empêcher 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 trappe d'évacuation pour de rares circonstances.

Il y a plusieurs façons de faire la dernière valeur d'un Sujet ou d'Observables dans un "Rx-y" façon:

  1. À l'aide de BehaviorSubject: Mais en fait à y souscrire. Lorsque vous tout d'abord vous abonner BehaviorSubject il sera synchrone envoyer la valeur précédente il a reçu ou a été initialisé avec.
  2. À l'aide d'un ReplaySubject(N): Cela cache N valeurs et les relire pour les nouveaux abonnés.
  3. A.withLatestFrom(B): Utiliser cet opérateur pour obtenir la valeur la plus récente à partir d'observables B lorsque observables A émet. Vous donnera à la fois des valeurs dans un tableau [a, b].
  4. A.combineLatest(B): Utiliser cet opérateur pour obtenir les valeurs les plus récentes de A et B chaque fois que l' A ou B émet. Vous donnera à la fois des valeurs dans un tableau.
  5. shareReplay(): Rend un Observables de multidiffusion à travers un ReplaySubject, mais qui permet de recommencer l'observables sur erreur. (En gros, il vous donne cette promesse-y comportement de mise en cache).
  6. publishReplay(), publishBehavior(initialValue), multicast(subject: BehaviorSubject | ReplaySubject),, etc: d'Autres opérateurs que l'effet de levier BehaviorSubject et ReplaySubject. Saveurs différentes de la même chose, ils se sont contentés de multidiffusion le source observable par le fait de rediriger toutes les notifications par l'intermédiaire d'un objet. Vous devez appeler connect() pour vous abonner à la source avec le sujet.

20voto

Kfir Erez Points 269

J'ai eu la même situation où la fin des abonnés s'abonner à l'Objet après sa valeur est arrivé.

J'ai trouvé ReplaySubject qui est similaire à BehaviorSubject fonctionne comme un charme dans ce cas. Et voici un lien pour mieux expliquer: http://reactivex.io/rxjs/manual/overview.html#replaysubject

3voto

Molp Burnbright Points 89

J'ai rencontré le même problème dans les composants enfants, où il devait initialement avoir la valeur actuelle de Subject, puis souscrire à Subject pour écouter les modifications. Je maintiens simplement la valeur actuelle dans le service afin qu'elle soit accessible aux composants, 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, à savoir:

 sessionStorage.isLoggedIn
 

Pas sûr que ce soit la bonne pratique :)

0voto

Slawa Points 137

Vous pouvez stocker la dernière valeur émise séparément de l'Observable. Puis lisez-le quand vous en aurez besoin.

 let lastValue: number;

const subscription = new Service().start();
subscription
    .subscribe((data) => {
        lastValue = data;
    }
);
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X