Tengo un servicio 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);
});
}
}
Todo funciona muy bien. Pero tengo otro componente que no necesita suscribirse, solo necesita obtener el valor actual de isLoggedIn en un momento determinado. ¿Cómo puedo hacer esto?
javascript
angular
rxjs
Baconbeastnz
fuente
fuente
getValue()
es una GRAN bandera roja que estás haciendo algo mal. Está ahí como una escotilla de escape. En general, todo lo que haga con RxJS debe ser declarativo.getValue()
Es imprescindible. Si está usandogetValue()
, hay un 99.9% de posibilidades de que esté haciendo algo mal o extraño.BehaviorSubject<boolean>(false)
y me gusta alternar?foo$
era unBehaviorSubject
(es decir, se define comoObservable
y tal vez hace calor o frío de una fuente diferida). Sin embargo, ya que luego pasa a usar.next
el$foo
mismo que significa que su aplicación se basa en que siendo unaBehaviorSubject
por lo que no hay justificación para el uso no sólo.value
para obtener el valor actual en el primer lugar.La única forma en que debe estar recibiendo los valores "de" un observable / El sujeto está con subscribe!
Si está utilizando
getValue()
, está haciendo algo imperativo en el paradigma declarativo. Está ahí como una escotilla de escape, pero el 99.9% del tiempo NO debe usargetValue()
. Hay algunas cosas interesantes quegetValue()
harán: arrojará un error si el sujeto se ha dado de baja, evitará que obtenga un valor si el sujeto está muerto porque está equivocado, etc. Pero, de nuevo, está ahí como un escape eclosionan por raras circunstancias.Hay varias formas de obtener el último valor de un sujeto u observable de forma "Rx-y":
BehaviorSubject
: Pero en realidad suscribiéndose a él . Cuando se suscribe por primeraBehaviorSubject
vez, enviará sincrónicamente el valor anterior que recibió o con el que se inicializó.ReplaySubject(N)
: Esto almacenará en caché losN
valores y los reproducirá a los nuevos suscriptores.A.withLatestFrom(B)
: Utilice este operador para obtener el valor más reciente de observableB
cuando seA
emite observable . Le dará ambos valores en una matriz[a, b]
.A.combineLatest(B)
: Utilice este operador para obtener los valores más recientesA
yB
cada vez que emiteA
oB
emite. Le dará ambos valores en una matriz.shareReplay()
: Realiza una multidifusión observable a través de aReplaySubject
, pero le permite volver a intentar la observable en caso de error. (Básicamente le da ese comportamiento prometedor de almacenamiento en caché).publishReplay()
,publishBehavior(initialValue)
,multicast(subject: BehaviorSubject | ReplaySubject)
, Etc: Otros operadores que aprovechanBehaviorSubject
yReplaySubject
. Diferentes sabores de la misma cosa, básicamente multidifunden la fuente observable al canalizar todas las notificaciones a través de un tema. Debe llamarconnect()
para suscribirse a la fuente con el tema.fuente
click$.mergeMap(() => behaviorSubject.take(1))
para resolver su problema.AuthenticationService
que usa unBehaviourSubject
para almacenar el estado de inicio de sesión actual (boolean
true
ofalse
). Expone unisLoggedIn$
observable para los suscriptores que desean saber cuándo cambia el estado. También expone unaget isLoggedIn()
propiedad, que devuelve el estado de inicio de sesión actual llamandogetValue()
al subyacenteBehaviourSubject
; esto lo utiliza mi guardia de autenticación para verificar el estado actual. Esto me parece un uso sensato degetValue()
...Tuve una situación similar en la que los suscriptores tardíos se suscriben al Asunto después de que llegó su valor.
Encontré ReplaySubject, que es similar a BehaviorSubject, funciona de maravilla en este caso. Y aquí hay un enlace para una mejor explicación: http://reactivex.io/rxjs/manual/overview.html#replaysubject
fuente
next()
función aún no se ha invocado, mientras que BehaviourSubject sí lo hace. La emisión inmediata es muy útil para aplicar valores predeterminados a una vista, cuando BehaviourSubject se usa como la fuente de datos observable en un servicio, por ejemploPuede consultar el artículo completo sobre cómo implementarlo desde aquí. https://www.imkrish.com/how-to-get-current-value-of-observable-in-a-clean-way/
fuente
Encontré el mismo problema en componentes secundarios donde inicialmente tendría que tener el valor actual del Asunto, luego suscribirse al Asunto para escuchar los cambios. Solo mantengo el valor actual en el Servicio para que esté disponible para que los componentes accedan, por ejemplo:
Un componente que necesita el valor actual podría acceder desde el servicio, es decir:
No estoy seguro si esta es la práctica correcta :)
fuente
async
tubería.Una similares buscando respuesta fue downvoted. Pero creo que puedo justificar lo que estoy sugiriendo aquí para casos limitados.
Si bien es cierto que un observable no tiene un valor actual , a menudo tendrá un valor disponible de inmediato . Por ejemplo, con las tiendas redux / flux / akita puede solicitar datos de una tienda central, en función de una cantidad de observables y ese valor generalmente estará disponible de inmediato.
Si este es el caso, entonces cuando usted
subscribe
, el valor volverá inmediatamente.Entonces, digamos que recibió una llamada a un servicio, y al finalizar desea obtener el último valor de algo de su tienda, que posiblemente no emita :
Puede intentar hacer esto (y debe mantener todo lo posible 'cosas dentro de las tuberías'):
El problema con esto es que se bloqueará hasta que el observable secundario emita un valor, que potencialmente nunca podría ser.
Recientemente me encontré necesitando evaluar un observable solo si un valor estaba disponible de inmediato , y lo que es más importante, necesitaba poder detectar si no lo estaba. Terminé haciendo esto:
Tenga en cuenta que para todo lo anterior, estoy usando
subscribe
para obtener el valor (como comenta @Ben). No usar una.value
propiedad, incluso si tuviera unBehaviorSubject
.fuente
Aunque puede sonar excesivo, esta es solo otra solución "posible" para mantener el tipo Observable y reducir la repetitiva ...
Siempre puede crear un getter de extensión para obtener el valor actual de un Observable.
Para hacer esto, necesitaría extender la
Observable<T>
interfaz en unglobal.d.ts
archivo de declaración de tipings. Luego implemente el getter de extensión en unobservable.extension.ts
archivo y finalmente incluya ambos tipos y archivo de extensión en su aplicación.Puede consultar esta Respuesta de StackOverflow para saber cómo incluir las extensiones en su aplicación Angular.
fuente
Puede almacenar el último valor emitido por separado del Observable. Luego léelo cuando sea necesario.
fuente
La mejor manera de hacer esto es usar
Behaviur Subject
, aquí hay un ejemplo:fuente
Se puede crear una suscripción y después de tomar el primer elemento emitido destruido. Pipe es una función que utiliza un Observable como entrada y devuelve otro Observable como salida, sin modificar el primer observable. Angular 8.1.0. Paquetes:
"rxjs": "6.5.3"
,"rxjs-observable": "0.0.7"
fuente