Is there any way to cancel previous async action in mobx-state-tree (Similar to takeLatest in redux-saga)

735 Views Asked by At

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.

1

There are 1 best solutions below

0
On BEST ANSWER

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()
  }

  // ...
}