Search code examples
javascriptreactjsreduxredux-toolkitreact-state-management

How to correctly handle loading state in redux toolkit crud


I want to know the best way for handling the loading state in redux-toolkit.

I have this slice and here I can create a post, delete a post, get all posts. And as I think, for all these operations I need to handle a loading state. So when the user waits for posts I can show a loader and if he creates a post I want to show a loader to him which indicates that the post is creating.

That's what I have

export const posts = createSlice({
  name: "posts",
  initialState : {posts: [], status: null},
  reducers: {},
  extraReducers: {
    [createPost.pending]: (state, action) => {
      state.status = "loading"; <==== how to do this.
    },
    [createPost.fulfilled]: (state, action) => {
      state.status = "success"; <==== how to do this
    },
    [createPost.rejected]: (state, action) => {
      state.status = "failed"; <==== how to do this
    },

    [getPosts.pending]: (state, action) => {
      state.status = "loading"; <==== how to do this
    },
    [getPosts.fulfilled]: (state, action) => {
      state.status = "success"; <==== how to do this
      state.posts = action.payload.data;
    },
    [getPosts.rejected]: (state, action) => {
      state.status = "failed"; <==== how to do this
    },

    [deletePost.pending]: (state, action) => {
      state.status = "loading"; <==== how to do this
    },
    [deletePost.fulfilled]: (state, action) => {
      state.status = "success"; <==== how to do this
      state.posts = state.posts.filter(el => el.id !== action.payload);
    },
    [deletePost.rejected]: (state, action) => {
      state.status = "failed"; <==== how to do this
    }, 

    [getPostById.pending]: (state, action) => {
      state.status = "loading"; <==== how to do this
    },
    [getPostById.fulfilled]: (state, action) => {
      state.status = "success"; <==== how to do this
      state.post = action.payload;
    },
    [getPostById.rejected]: (state, action) => {
      state.status = "failed"; <==== how to do this
    },
  },
});

I can also create two more keys in my initial state for every crud operation like (createLoadingState, deleteLoadingState) but I think that's not right

I think that I can just make something like this:

[createPost.pending]: (state, action) => {
  state.status = "creating_post_loading";
},
[createPost.fulfilled]: (state, action) => {
  state.status = "creating_post_success";
},
[createPost.rejected]: (state, action) => {
  state.status = "creating_post_failed";
},


[getPosts.pending]: (state, action) => {
  state.status = "get_posts_loading";
},
[getPosts.fulfilled]: (state, action) => {
  state.status = "get_posts_success";
  state.posts = action.payload.data;
},
[getPosts.rejected]: (state, action) => {
  state.status = "get_posts_failed";
},

BUT then I will have to remember every single name, so this approach seems very bad for me.

The best idea that came up to my mind is to have this initialState

const initialState = {
  posts: [],
  loading: null, <==== added
  error: null, <==== added
  selectedPost: {},
};

and now when I fetch all posts I just write state.loading = true BUT in CREATE POST I make state.loading = false since I don't want my posts to reload on the page if someone creates the post but in this way, I won't show a loader state for the created post since the loading state is false.

I can also create separate slices for each operation with its own loadingState but don't know if it is right.

What I mean, in my react component I check if posts are loading, if so then I show a loader and if not then I will show the fetched data but if I have the same loading state for all my crud operations then whenever the user adds/deletes/updates a post it will trigger the loading state for everything.

If you have github repos where I can find the best practices, I will be very happy if you can send me those.


Solution

  • You would either need many different loading indicators or even multiple slices, both which might be a lot of work. Redux Toolkit also contains a data fetching/api cache abstraction called "RTK Query" that automates all of that, so I recommend you read the docs on that.

    https://redux-toolkit.js.org/rtk-query/overview