I have a code to fetch book and library card associated with it:
// mimic http requests
const fetchBook = (bookId: number) => {
const title = 'Book' + bookId;
return timer(200).pipe(mapTo({ bookId, title }));
}
const fetchLibraryCard = (bookId: number) => {
const borrowerName = 'Borrower of Book' + bookId;
return timer(300).pipe(mapTo({ borrowerName }));
}
const bookId$ = new Subject<number>();
const book$ = bookId$.pipe(
switchMap(bookId => fetchBook(bookId)),
shareReplay(1)
);
// e.g. 'Refresh library card' button
const libraryCardUpdater$ = new BehaviorSubject<void>(undefined);
const libraryCard$ = combineLatest([bookId$, libraryCardUpdater$]).pipe(
switchMap(([bookId]) => fetchLibraryCard(bookId)),
shareReplay(1)
);
combineLatest([book$, libraryCard$]).subscribe(([book, libraryCard]) => {
console.log('book:', book.title, '| borrower:', libraryCard.borrowerName)
})
bookId$.next(1);
setTimeout(() => bookId$.next(2), 500);
setTimeout(() => libraryCardUpdater$.next(), 1000);
setTimeout(() => bookId$.next(3), 1500);
The problem that I get inconsistent state in subscriber:
book: Book1 | borrower: Borrower of Book1 <-- OK
book: Book2 | borrower: Borrower of Book1 <-- Not OK
book: Book2 | borrower: Borrower of Book2 <-- OK
book: Book2 | borrower: Borrower of Book2 <-- OK, but redundant
book: Book3 | borrower: Borrower of Book2 <-- Not OK
book: Book3 | borrower: Borrower of Book3 <-- OK
I think about something like pushing undefined
to libraryCard$
at the same moment when bookId$
is changed.
But how to do that in a reactive manner?
Update:
Library card should be always consistent with fetched book (or be undefined
at loading time). bookId$
can be changed by user action at any time. Also library card can be updated at any time manually by user (libraryCardUpdater$
). libraryCardUpdater$
emitting should re-fetch card, but shouldn't re-fetch book
Update2: I just realized that library card can be fetched sequentially after book. It is acceptable, although not perfect solution for end-user.