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 a juste besoin d'obtenir la valeur actuelle d'isLoggedIn à un certain moment. Comment puis-je faire ceci?
javascript
angular
rxjs
Baconbeastnz
la source
la source
getValue()
un drapeau rouge ÉNORME vous fait quelque chose de mal. Il est là comme une trappe d'évacuation. Généralement, tout ce que vous faites avec RxJS doit être déclaratif.getValue()
est impératif. Si vous utilisezgetValue()
, il y a 99,9% de chances que vous fassiez quelque chose de mal ou de bizarre.BehaviorSubject<boolean>(false)
et que je souhaite le basculer?foo$
c'était unBehaviorSubject
(c'est-à-dire qu'il est défini commeObservable
et peut-être qu'il fait chaud ou froid à partir d'une source différée). Cependant , puisque vous allez ensuite à utiliser.next
sur$foo
lui - même qui signifie que votre mise en œuvre repose sur elle étant unBehaviorSubject
donc il n'y a aucune raison pour ne pas utiliser simplement.value
pour obtenir la valeur actuelle en premier lieu.La seule façon que vous devriez être obtenir des valeurs « sur » un Observable / sujet est subscribe!
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 l'utilisergetValue()
. Il y a quelques choses intéressantes quigetValue()
faire: cela générera une erreur si le sujet a été désabonné, il vous empêchera d'obtenir une valeur si le sujet est mort parce qu'il est erroné, etc. Mais, encore une fois, il est là comme une échappatoire trappe pour de rares circonstances.Il existe plusieurs façons d'obtenir la dernière valeur d'un sujet ou observable de manière "Rx-y":
BehaviorSubject
: mais en y souscrivant . Lorsque vous vous abonnez pour la première fois àBehaviorSubject
il envoie de manière synchrone la valeur précédente qu'il a reçue ou a été initialisée avec.ReplaySubject(N)
: cela mettra en cacheN
valeurs et les rejouera aux nouveaux abonnés.A.withLatestFrom(B)
: Utilisez cet opérateur pour obtenir la valeur la plus récente de l'observableB
lors de sonA
émission. Vous donnera les deux valeurs dans un tableau[a, b]
.A.combineLatest(B)
: Utilisez cet opérateur pour obtenir les valeurs les plus récentes deA
etB
chaque fois que ce soitA
ouB
émet. Vous donnera les deux valeurs dans un tableau.shareReplay()
: Effectue une multidiffusion observable via unReplaySubject
, mais vous permet de réessayer l'observable en cas d'erreur. (Fondamentalement, cela vous donne ce comportement de mise en cache prometteur).publishReplay()
,publishBehavior(initialValue)
,multicast(subject: BehaviorSubject | ReplaySubject)
, Etc: D' autres opérateurs qui tirent partiBehaviorSubject
etReplaySubject
. Différentes saveurs de la même chose, elles diffusent essentiellement la source observable en canalisant toutes les notifications via un sujet. Vous devez appelerconnect()
pour vous abonner à la source avec le sujet.la source
click$.mergeMap(() => behaviorSubject.take(1))
résoudre votre problème.AuthenticationService
qui utilise unBehaviourSubject
pour stocker l'état actuellement connecté (boolean
true
oufalse
). Il expose unisLoggedIn$
observable pour les abonnés qui veulent savoir quand l'état change. Il expose également uneget isLoggedIn()
propriété, qui renvoie l'état actuellement connecté en appelantgetValue()
le sousBehaviourSubject
- jacent - cela est utilisé par mon garde d'authentification pour vérifier l'état actuel. Cela me semble une utilisation sensée degetValue()
...?J'ai eu une situation similaire 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 pour une meilleure explication: http://reactivex.io/rxjs/manual/overview.html#replaysubject
la source
next()
fonction n'a pas encore été invoquée, contrairement à BehaviourSubject. L'émission immédiate est très pratique pour appliquer des valeurs par défaut à une vue, lorsque le BehaviourSubject est utilisé comme source de données observable dans un service par exempleVous pouvez consulter l'article complet sur la façon de l'implémenter à partir d'ici. https://www.imkrish.com/how-to-get-current-value-of-observable-in-a-clean-way/
la source
J'ai rencontré le même problème dans les composants enfants où initialement il devrait avoir la valeur actuelle du sujet, puis s'abonner au sujet pour écouter les modifications. Je conserve simplement la valeur actuelle du service afin qu'elle soit accessible aux composants, par exemple:
Un composant qui a besoin de la valeur actuelle pourrait simplement y accéder à partir du service, c'est-à-dire:
Je ne sais pas si c'est la bonne pratique :)
la source
async
tuyau.Une semblable recherche réponse a été downvoted. Mais je pense que je peux justifier ce que je propose ici pour des cas limités.
S'il est vrai qu'un observable n'a pas de valeur actuelle , il aura très souvent une valeur immédiatement disponible . Par exemple, avec les magasins redux / flux / akita, vous pouvez demander des données à un magasin central, sur la base d'un certain nombre d'observables et cette valeur sera généralement immédiatement disponible.
Si tel est le cas, lorsque vous
subscribe
, la valeur reviendra immédiatement.Supposons donc que vous ayez appelé un service et, une fois terminé, vous souhaitez obtenir la dernière valeur de quelque chose de votre magasin, qui pourrait ne pas émettre :
Vous pourriez essayer de le faire (et vous devriez autant que possible garder les choses «à l'intérieur des tuyaux»):
Le problème avec cela est qu'il se bloquera jusqu'à ce que l'observable secondaire émette une valeur, qui pourrait potentiellement ne jamais l'être.
Je me suis retrouvé récemment à avoir besoin d'évaluer un observable uniquement si une valeur était immédiatement disponible , et plus important encore, j'avais besoin de pouvoir détecter si ce n'était pas le cas. J'ai fini par faire ça:
Notez que pour tout ce qui précède, j'utilise
subscribe
pour obtenir la valeur (comme @Ben en parle). Ne pas utiliser de.value
propriété, même si j'en avaisBehaviorSubject
.la source
Bien que cela puisse sembler exagéré, ce n'est qu'une autre solution "possible" pour garder le type observable et réduire le passe-partout ...
Vous pouvez toujours créer un getter d'extension pour obtenir la valeur actuelle d'un observable.
Pour ce faire, vous devez étendre l'
Observable<T>
interface dans unglobal.d.ts
fichier de déclaration de typage. Ensuite, implémentez l' extension getter dans unobservable.extension.ts
fichier et incluez enfin à la fois les saisies et le fichier d'extension dans votre application.Vous pouvez vous référer à cette réponse StackOverflow pour savoir comment inclure les extensions dans votre application angulaire.
la source
Vous pouvez stocker la dernière valeur émise séparément de l'Observable. Lisez-le ensuite au besoin.
la source
La meilleure façon de le faire est d'utiliser
Behaviur Subject
, voici un exemple:la source
Un abonnement peut être créé et après avoir pris le premier élément émis détruit. Pipe est une fonction qui utilise un observable comme entrée et renvoie un autre observable comme sortie, sans modifier le premier observable. Angulaire 8.1.0. Forfaits:
"rxjs": "6.5.3"
,"rxjs-observable": "0.0.7"
la source