Skip to content

Add a utility to follow thunk network status #550

@HHK1

Description

@HHK1

Possibly related issues:

#418

Motivation

Something I've been doing over and over when I'm creating a thunk, is to add a loading and error properties in the corresponding slice of my store, in a similar fashion as what's described in the tutorial.

In the most simple implementations, loading is a boolean, or in more advanced ones an enum like this one from the Apollo library: https://github.com/apollographql/apollo-client/blob/master/src/core/networkStatus.ts

I've found it very useful when using Apollo to have this advanced loading state/ network status provided by default, especially for paginated requests.
Would it fall in the scope for Redux-toolkit to provide a mechanism to create those for a thunk ?

Implementation suggestions

I've done a simple example where I'm creating a reducer given a thunk (returned from createAsyncThunk.) Handling of the various loading state, concurrent requests etc. is not complete (fechMore, polling are missing) but all that logic could be implemented here and provide a nice default to properly handle loading state.


export enum LoadingStatus {
  /** Initial Load, no previous data */
  loading = 1,

  /** Data has been refteched manually */
  refetch = 2,

  /** Data is paginated and another page is loading */
  fetchMore = 3,

  /** Data is polling and a new request has started */
  poll = 4,

  /** Loaded successfully */
  ready = 5,

  /** Network call failed  */
  error = 6,
}


export interface ThunkMetaState {
  loading: LoadingStatus | null;
  error: SerializedError | null;
}

const initialState: ThunkMetaState = {
  loading: null,
  error: null,
};

export const createThunkMetaReducer = <Return, ThunkArg>(
  thunk: AsyncThunk<Return, ThunkArg>
): Reducer<ThunkMetaState, AnyAction> => {
  const metaReducer = createReducer<ThunkMetaState>(initialState, builder => {
    builder.addCase(thunk.pending, state => {
      state.loading = state.loading !== null ? LoadingStatus.refetch : LoadingStatus.loading;
      state.error = null;
    });
    builder.addCase(thunk.fulfilled, state => {
      state.loading = LoadingStatus.ready;
      state.error = null;
    });
    builder.addCase(thunk.rejected, (state, action) => {
      state.loading = LoadingStatus.error;
      state.error = action.error;
    });
  });

  return metaReducer;
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions