Alex Biro
Alex Biro

Reputation: 1227

rxjs shareReplay with refCount off doesn't subscribe to the source until the first downstream subscriber

export class DataService {
  private readonly dataSubject: Subject<Data> = new Subject();

  public readonly myData$: Observable<Data>;

  constructor() {
    this.myData$ = this.dataSubject.asObservable().pipe(
      shareReplay({
        bufferSize: 1,
        refCount: false,
      }),
    );
    // this would solve the problem, but is an ugly workaround
    // this.myData$.subscribe();
  }

  update(data: Data) {
    this.dataSubject.next(data);
  }

There's this global singleton DataService, which should provide a certain data to various parts of the application. When the consumers subscribe, they should immediately receive the last value, and the new ones in the future.

My understanding was the following: if I add the shareReplay as shown above, with refCounting turned off, it will subscribe to its upstream observable (ie. the dataSubject in this case) immediately and keep the last value, and when there are downstream subscribers, emit the last value and also any future ones.

What happens instead, if I understand correctly: if the first downstream subscriber comes later than the first value in source the subject, than the first value is lost, because at that point the shareReplay was not subscribed to the subject, so it didn't collect the previous value. If I immediately add a downstream subscriber, that fixes the problem, but that's a bit ugly.

I was able to solve my issue with the workaround below which is a bit nicer, where I moved the replay functionality into the subject itself, so that it already keeps the last values regardless of the subscribers. But still would like to know what I might be missing how the shareReplay works, or if I made a mistake in the code above.

export class DataService {
  private readonly dataSubject: Subject<Data> = new ReplaySubject();

  public readonly myData$: Observable<Data>;

  constructor() {
    this.myData$ = this.dataSubject.asObservable().pipe(
      share(),
    );
  }

  update(data: Data) {
    this.dataSubject.next(data);
  }

Upvotes: 2

Views: 4411

Answers (1)

Chrillewoodz
Chrillewoodz

Reputation: 28328

When using a Subject, if the next happens before a subscribe, then the value is lost. So new subscribers can't get the last value. Therefore it's recommended to use a ReplaySubject or a BehaviorSubject instead to avoid losing values like this.

To answer the actual question, as explained in this article about shareReplay:

refCount: false means that upon first subscription to ReplaySubject it will subscribe to Source

No, it will not subscribe immediately.

Upvotes: 3

Related Questions