Currently, I am working on my react-native application using MST as a state management library.
Now I have encountered an issue where the app has a chance to fire 2 similar API calls. The 1st API responded after the 2nd one, which caused the data to be overridden by an outdated response.
In redux-saga, we can use takeLatest
to make sure we get the data from the latest request. I am looking for similar function in MST to address the problem.
I have found that there's Axios' cancel token to cancel the API calls, but I want to see is there any way in a more generic async way to solve it.
As far as I know there is no build in features like that in MobX or MST, so you would need to implement it by yourself.
Generic way I usually use to cancel promises is this one (credit to https://wanago.io):
class RaceConditionGuard {
private lastPromise: PromiseLike<unknown> | null = null;
getGuardedPromise<T>(promise: PromiseLike<T>) {
this.lastPromise = promise;
return this.lastPromise.then(this.preventRaceCondition()) as Promise<T>;
}
preventRaceCondition() {
const currentPromise = this.lastPromise;
return (response: unknown) => {
if (this.lastPromise !== currentPromise) {
return new Promise(() => null);
}
return response;
};
}
cancel = () => {
this.lastPromise = null;
};
}
And the usage, assuming you have some class based store, for example:
class SomeStore {
raceConditionGuard = new RaceConditionGuard();
loadItems = () => {
// Previous call will be automatically canceled (it will never resolve actually)
this.raceConditionGuard
// Wrap your async operation
.getGuardedPromise(fetchSomething())
// Handle result somehow
.then(this.handleResult);
};
// Or you can cancel manually
cancelLoading = () => {
this.raceConditionGuard.cancel()
}
// ...
}