Reputation: 658
I have implemented this simple store:
export class BookStore extends Store<BookState> implements OnDestroy {
private _sub = new Subscription();
constructor(private api: BookApiService, private data: DataTableService) {
super(new BookState());
this._sub.add(this.data.state.subscribe(val => {
this.fetchBooks(val);
}));
}
fetchBooks(body: any): void {
this._sub.add(this.api.getBooks(body).subscribe(val => {
this.setState({
...this.state,
books: val.Data,
});
}));
}
ngOnDestroy(): void {
this._sub.unsubscribe();
}
}
class BookState extends BaseState {
books: Book[];
}
In the constructor of that store, I subscribe to the data filter observable (an object with various filter DTOs, which changes depending on the button user has pressed). Problem is, that in this case race conditions occur. If I quickly press on the 2 different filter buttons, sometimes the data is being overwritten with the one returned from the first button click (should be from second).
Here's the getBooks method from api service:
getBooks(body): Observable<BaseResource<T>> {
return this.httpClient
.post<BaseResource<T>>(`${this._host}/${this.base}/${this.name}/getBooks`, body);
}
Is it possible to make this fetchBooks function from constructor:
this._sub.add(this.data.state.subscribe(val => {
this.fetchBooks(val);
}));
To execute synchronously? I've read somewhere, that the switchMap operator is the way to go, but I can't wrap my head around it. Could somebody please point me in the right direction?
Upvotes: 1
Views: 5597
Reputation: 3236
Have a look to switchMap
operator. It is designed to ignore last HTTP call if a new one is triggered.
Here is an exemple to autocomplete an input from wikipedia pages:
this.userInputEvent$.pipe(
debounceTime(300), // waits 300ms before calling server, to do only one call when user stops typing
distinctUntilChanged(), // do not call server if input did not change since last call
switchMap((term: string) => this.wikipediaService.search(term)) // switchs the user-input observable to an http call observable depending on the user input. Ignores last call if a new one is triggered before last one is received.
).subscribe(httpResults => this.items = httpResults);
Upvotes: 2
Reputation: 2330
Try this.
apiSubscription: Subscription;
fetchBooks(body: any): void {
if (this.apiSubscription) {
this.apiSubscription.unsubscribe()
}
this.apiSubscription = this.api.getBooks(body).subscribe(val => {
this.setState({
...this.state,
books: val.Data,
});
});
this._sub.add(this.apiSubscription);
}
Upvotes: 1