-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Possibly related issues:
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;
};