Ich habe einen Angular 2-Dienst:
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);
});
}
}
Alles funktioniert super. Aber ich habe eine andere Komponente, die nicht abonniert werden muss, sondern nur den aktuellen Wert von isLoggedIn zu einem bestimmten Zeitpunkt abrufen muss. Wie kann ich das machen?
javascript
angular
rxjs
Baconbeastnz
quelle
quelle
getValue()
eine RIESIGE rote Fahne verwenden, machen Sie etwas falsch. Es ist dort als Notluke. Im Allgemeinen sollte alles, was Sie mit RxJS tun, deklarativ sein.getValue()
ist zwingend erforderlich. Wenn Sie verwendengetValue()
, besteht eine Wahrscheinlichkeit von 99,9%, dass Sie etwas falsch oder seltsam machen.BehaviorSubject<boolean>(false)
und es gerne umschalten möchte?foo$
ein istBehaviorSubject
(dh es ist definiert alsObservable
und vielleicht ist es heiß oder kalt von einer zurückgestellten Quelle). Jedoch , da Sie dann Gebrauch machen.next
auf$foo
sich selbst , das bedeutet , dass Ihre Implementierung beruht auf es ist eineBehaviorSubject
so gibt es keine Rechtfertigung für die nicht nur mit.value
den aktuellen Wert an erster Stelle zu bekommen.Der einzige Weg , Sie sollten Werte „aus“ eine beobachtbare / Fach bekommen ist mit abonnieren!
Wenn Sie verwenden
getValue()
, tun Sie etwas Notwendiges im deklarativen Paradigma. Es ist dort als Notluke, aber 99,9% der Zeit sollten Sie NICHT verwendengetValue()
. Es gibt ein paar interessante Dinge,getValue()
die zu tun sind: Es wird ein Fehler ausgegeben, wenn das Thema abgemeldet wurde, es wird verhindert, dass Sie einen Wert erhalten, wenn das Thema tot ist, weil es fehlerhaft ist usw. Aber es ist wieder als Flucht da Luke für seltene Umstände.Es gibt verschiedene Möglichkeiten, um den neuesten Wert von einem Subjekt oder Observable auf "Rx-y" Weise zu erhalten:
BehaviorSubject
: Aber tatsächlich abonnieren . Wenn Sie es zum ersten Mal abonnieren,BehaviorSubject
wird synchron der vorherige Wert gesendet, den es empfangen hat oder mit dem es initialisiert wurde.ReplaySubject(N)
: Dadurch werdenN
Werte zwischengespeichert und an neue Abonnenten wiedergegeben.A.withLatestFrom(B)
: Verwenden Sie diesen Operator, um den neuesten Wert von Observable zu erhalten,B
wenn ObservableA
emittiert. Gibt Ihnen beide Werte in einem Array[a, b]
.A.combineLatest(B)
: Verwenden Sie die aktuellsten Werte von bekommen dieser OperatorA
undB
jedes Mal entwederA
oderB
aussendet. Gibt Ihnen beide Werte in einem Array.shareReplay()
: Erstellt ein Observable-Multicast über aReplaySubject
, ermöglicht es Ihnen jedoch, das Observable bei einem Fehler erneut zu versuchen. (Grundsätzlich gibt es Ihnen das vielversprechende Caching-Verhalten).publishReplay()
,publishBehavior(initialValue)
,multicast(subject: BehaviorSubject | ReplaySubject)
, Etc: Andere Betreiber , die HebelwirkungBehaviorSubject
undReplaySubject
. Verschiedene Geschmacksrichtungen derselben Sache, sie senden im Grunde genommen die beobachtbare Quelle per Multicast, indem sie alle Benachrichtigungen durch ein Thema leiten. Sie müssen anrufenconnect()
, um die Quelle mit dem Betreff zu abonnieren.quelle
click$.mergeMap(() => behaviorSubject.take(1))
Ihr Problem lösen.AuthenticationService
die a verwendetBehaviourSubject
, um den aktuell angemeldeten Status (boolean
true
oderfalse
) zu speichern . Es stellt einisLoggedIn$
Observable für Abonnenten bereit, die wissen möchten, wann sich der Status ändert. Außerdem wird eineget isLoggedIn()
Eigenschaft verfügbar gemacht , die den aktuellen angemeldeten Status durch AufrufengetValue()
des Basiswerts zurückgibt.BehaviourSubject
Dies wird von meinem Authentifizierungsschutz verwendet, um den aktuellen Status zu überprüfen. Dies scheintgetValue()
mir eine vernünftige Verwendung zu sein ...?Ich hatte eine ähnliche Situation, in der verspätete Abonnenten das Thema abonnierten, nachdem sein Wert angekommen war.
Ich habe festgestellt, dass ReplaySubject, das BehaviorSubject ähnelt, in diesem Fall wie ein Zauber wirkt. Und hier ist ein Link zur besseren Erklärung: http://reactivex.io/rxjs/manual/overview.html#replaysubject
quelle
next()
Funktion noch nicht aufgerufen wurde, wohingegen BehaviourSubject dies tut. Die sofortige Ausgabe ist sehr praktisch, um Standardwerte auf eine Ansicht anzuwenden, wenn das BehaviourSubject als Datenquelle verwendet wird, die beispielsweise in einem Dienst beobachtet werden kannDen vollständigen Artikel zur Implementierung finden Sie hier. https://www.imkrish.com/how-to-get-current-value-of-observable-in-a-clean-way/
quelle
Ich hatte das gleiche Problem bei untergeordneten Komponenten, bei denen zunächst der aktuelle Wert des Betreffs angegeben und dann der Betreff abonniert werden musste, um Änderungen zu hören. Ich behalte nur den aktuellen Wert im Service bei, damit Komponenten darauf zugreifen können, z. B.:
Eine Komponente, die den aktuellen Wert benötigt, kann dann über den Dienst darauf zugreifen, dh:
Ich bin mir nicht sicher, ob dies die richtige Praxis ist :)
quelle
async
Pipe verwenden.Eine ähnlich aussehende Antwort wurde abgelehnt. Aber ich denke, ich kann rechtfertigen, was ich hier für begrenzte Fälle vorschlage.
Es stimmt zwar, dass ein Observable keinen aktuellen Wert hat, aber sehr oft hat es einen sofort verfügbaren Wert. Beispielsweise können Sie bei Redux / Flux / Akita-Speichern Daten von einem zentralen Speicher anfordern, die auf einer Reihe von Observablen basieren, und dieser Wert ist im Allgemeinen sofort verfügbar.
Wenn dies der Fall ist
subscribe
, wird der Wert sofort wieder angezeigt.Nehmen wir also an, Sie haben einen Anruf bei einem Dienstleister erhalten und möchten nach Abschluss den neuesten Wert von etwas aus Ihrem Geschäft abrufen, das möglicherweise nicht ausgegeben wird :
Sie könnten versuchen, dies zu tun (und Sie sollten die Dinge so weit wie möglich in Rohren aufbewahren):
Das Problem dabei ist, dass es blockiert, bis das sekundäre Observable einen Wert ausgibt, der möglicherweise niemals sein könnte.
Vor kurzem musste ich ein Observable nur dann bewerten, wenn ein Wert sofort verfügbar war , und was noch wichtiger war, ich musste erkennen können, ob dies nicht der Fall war. Am Ende habe ich das gemacht:
Beachten Sie, dass ich für alle oben genannten
subscribe
Punkte den Wert erhalte (wie in @Ben erläutert). Ich benutze keine.value
Immobilie, auch wenn ich eine hatteBehaviorSubject
.quelle
Obwohl es übertrieben klingen mag, ist dies nur eine weitere "mögliche" Lösung, um den Observable- Typ beizubehalten und die Boilerplate zu reduzieren ...
Sie können jederzeit einen Erweiterungs-Getter erstellen , um den aktuellen Wert eines Observable abzurufen.
Dazu müssten Sie die
Observable<T>
Schnittstelle in einerglobal.d.ts
Typisierungsdeklarationsdatei erweitern. Implementieren Sie dann den Erweiterungs-Getter in eineobservable.extension.ts
Datei und fügen Sie Ihrer Anwendung schließlich sowohl Typisierungen als auch Erweiterungsdateien hinzu.In dieser StackOverflow-Antwort erfahren Sie, wie Sie die Erweiterungen in Ihre Angular-Anwendung aufnehmen können.
quelle
Sie können den zuletzt ausgegebenen Wert getrennt vom Observable speichern. Dann lesen Sie es bei Bedarf.
quelle
Der beste Weg, dies zu tun, ist die Verwendung
Behaviur Subject
eines Beispiels:quelle
Ein Abonnement kann erstellt und nach Einnahme des ersten emittierten Gegenstands zerstört werden. Pipe ist eine Funktion, die eine Observable als Eingabe verwendet und eine andere Observable als Ausgabe zurückgibt, ohne die erste Observable zu ändern. Winkel 8.1.0. Pakete :
"rxjs": "6.5.3"
,"rxjs-observable": "0.0.7"
quelle