Search code examples
reduxredux-thunkredux-toolkit

Why an aborted thunk is not rejected imediatly, how can i handle loading


I'm trying to build a simple use case with ReduxToolkit :

  • Dispatching a thunk
  • Displaying a loader indicator
  • Abort the thunk if something happen before the last thunk finish running

I use an effect :

  useEffect(() => {
    const runningThunk = dispatch(asyncThunk());
    return () => {
      runningThunk.abort();
    };
  }, [dispatch, count]);

and a basic slice :

extraReducers: (builder) => {
    builder.addCase(asyncThunk.pending, (state) => {
      state.isLoading = true;
    });
    builder.addCase(asyncThunk.fulfilled, (state) => {
      state.isLoading = false;
    });
    builder.addCase(asyncThunk.rejected, (state) => {
      state.isLoading = false;
    });

When i run this code, the abort is called then the hook is re-runned and a new dispatch is called. So far so good.

But redux does not handle it the same way. The 2nd thunk is dispatched and the pending action is dispatched BEFORE the previous thunk is rejected.

1 - async-thunk/pending (Call 1)
2 - async-thunk/pending (Call 2)
3 - async-thunk/rejected (Call 1)
4 - async-thunk/fulfilled (Call 2)

This result in my loading indicator only displayed between step 1 and step 3 since the rejected thunk reset the state.

Is that a bug ? If this is the wanted behavior, how can i handle my problem ?

A sandbox reproducing the issue when we change the counter twice before the thunk ends.

https://codesandbox.io/s/wonderful-chaum-stgsn


Solution

  • It is not avoidable. A running thunk is asynchronous, and aborting it is asynchronous as well. Starting a thunk happens synchronously though.

    If you have concerns like this, you should track the requestId of the most recently started thunk in your store and only update your store when an action with this requestId comes along.

    See the first example on the createAsyncThunk api documentation