createAsyncThunk and extraReducers

ref –

  • https://blog.logrocket.com/using-redux-toolkits-createasyncthunk/
  • https://redux-toolkit.js.org/api/createAsyncThunk

Within createSlice, synchronous requests made to the store are handled in the reducers object while extraReducers handles asynchronous requests, which is our main focus.

For example…with reducers

They are functions that receive the current state, and an action object that was dispatched.

src/features/posts/postsSlice.js

We export our reducers from postsSlice.actions so others can use it to dispatch.

src/features/posts/postsSlice.js

In the UI layer, they are dispatched like so:

src/features/posts/ReactionButtons.js

On the other hand…what if we want the async version of it?

Asynchronous requests created with createAsyncThunk accept three parameters:

  • an action type string
  • a callback function (referred to as a payloadCreator)
  • options object

Taking the previous code block as a Redux store for a blog application, let’s examine getPosts:

We have our initial state.

posts/fetchPosts is the action type string in this case.

Whenever this function is dispatched from a component within our application, createAsyncThunk generates promise lifecycle action types using this string as a prefix:

  • pending: posts/fetchPosts/pending
  • fulfilled: posts/fetchPosts/fulfilled
  • rejected: posts/fetchPosts/rejected

On its initial call, createAsyncThunk dispatches the posts/getPosts/pending lifecycle action type. The payloadCreator then executes to return either a result or an error.

In the event of an error, posts/getPosts/rejected is dispatched and createAsyncThunk should either return a rejected promise containing an Error instance, a plain descriptive message, or a resolved promise with a RejectWithValue argument as returned by the thunkAPI.rejectWithValue function (more on thunkAPI and error handling momentarily).

If our data fetch is successful, the posts/getPosts/fulfilled action type gets dispatched.

src/features/posts/postsSlice.js

Notice that we change the status property of state. How and where is state used?
First, notice getPostsStatus. In PostsList, we call useSelector on getPostsStatus.

useSelector is simply a hook to access Redux store’s state. This hook takes a selector function (getPostsStatus) as an argument. The selector is called with the store state.
In our case, it is state.posts.

Furthermore since we want to look at status property, then we’re accessing state.posts.status.

In other words, if state.posts.status === ‘loading’…

src/features/posts/PostsList.js