I will provide two version of code snippet for better understaing:
1st one
const test = timer(0, 1000).pipe(shareReplay({ bufferSize: 1, refCount: true }));
const subscription1 = test.subscribe(
(value) => console.log('Subscription 1:', value),
(error) => console.error(error),
() => console.log('Subscription 1 completed'),
);
setTimeout(() => {
subscription1.unsubscribe();
}, 6000);
setTimeout(() => {
const subscription2 = test.subscribe(
(value) => console.log('Subscription 2:', value),
(error) => console.error(error),
() => console.log('Subscription 2 completed'),
);
}, 10000);
Main point of this code is to test how shareReply
works with refCount
set to true
. Behaviour is expected, since
subscription1
observable emits 5 times, then I unsubscribe, meaning refCount
will be 0 again for test
, what causes test
observable to drop the cache. When i subscribe with subscription2
the emission start with 0.
But if i use fromFetch
operator, cache of test
observable is not dropped, even if there are no active subscribers to test observable:
export const groupsRaw$ = fromFetch('/some_endpoint').pipe(
shareReplay({ bufferSize: 1, refCount: true }),
);
const subscription1 = groupsRaw$.subscribe(
(value) => console.log('Subscription 1:', value),
(error) => console.error(error),
() => console.log('Subscription 1 completed'),
);
setTimeout(() => {
subscription1.unsubscribe();
}, 6000);
setTimeout(() => {
const subscription2 = groupsRaw$.subscribe(
(value) => console.log('Subscription 2:', value),
(error) => console.error(error),
() => console.log('Subscription 2 completed'),
);
}, 10000);
There will be only one request in the network tab.
I expect that subscription2
on subscribe should refetch data, but it takes it from cache. But cache should be already dropped. What do i miss?
The behavior you are seeing doesn't have to do with using fromFetch
vs timer
, it has to do with the source completing vs not completing.
shareReplay
will cache the source observable for future subscribers if its source completes. (see this github issue for reference).
To achieve your desired behavior, you can use share
and specify resetOnComplete = true
:
share({
connector: () => new ReplaySubject(1),
resetOnComplete : true,
resetOnRefCountZero : true,
})
Here's a little StackBlitz you can play around with.
Since all the "reset" options are true
by default, you don't actually need to specify them. So you could simply do:
share({ connector: () => new ReplaySubject(1) })