Looking for the same functionality as BehaviorSubject
but without having to provide an initial value.
I often need to subscribe to a subject before my data gets loaded from whatever source I load it from. I also need the subscription to fire immediately after subscribing if and only if next()
was previously called on the subject and I expect it to show me the last emitted value, as well as be able to get the current value synchronously at any point in time, similar to the value
field of BehaviorSubject
.
Here's what I tried:
Subject
, but it doesn't emit the old value immediately after subscribing to it likeBehaviorSubject
and I can't retrieve the current value.ReplaySubject
with a buffer of size 1, but this also doesn't allow retrieval of the current value.BehaviorSubject.create()
instead ofnew BehaviorSubject<Whatever>(null)
but this just doesn't do anything when callingnext()
. No value is emitted and the subscription code never fires.BehaviorSubject
with.pipe(skip(1)).subscribe
but if I run this code after I callednext()
then I loose that old but valid value, only firing afternext
is called again.
The only solution I came up with is to extend the ReplaySubject
class to add a private field for the current value, which gets set when next()
is called, and a getter to retrieve it.
I always expect these values to be defined and valid, so I don't understand why I have to provide a default null/undefined value to BehaviourSubject
for an object type that I specifically expect to not be undefined/null and explicitly defined them accordingly, and then write an if statement in every subscription to check every time a new value is emitted if it is valid.
I also don't understand why must it emit that null value and cause each subscription to fire for no good reason each time I subscribe to the subject before I load the data.
So is there any alternative I have missed?
Edit: So far, the answer to my question seems to be that no, there isn't an equivalent. As such, I'm providing my work around for anyone who's looking for the same behavior:
import { ReplaySubject } from 'rxjs';
export class SensibleSubject<T>
{
private replaySubject: ReplaySubject<T>;
private _canGetValue = false;
private _value!: T;
public get value()
{
if (!this._canGetValue)
throw new Error("Attempted to retrieve value before it has been set!");
return this._value;
}
constructor()
{
this.replaySubject = new ReplaySubject<T>(1);
}
public next(value: T)
{
this._canGetValue = true;
this._value = value;
this.replaySubject.next(value);
}
public asObservable()
{
return this.replaySubject.asObservable();
}
public canGetValue()
{
return this._canGetValue;
}
}
Initially, I specified that I extended the ReplaySubject
class but, as crowmagnumb points out in his answer to Behaviour subject initial value null?, overriding next
on the ReplaySubject
somehow breaks it. I instead decided to wrap the ReplaySubject
and expose the desired methods and fields.