React with the Redux toolkit and CreateAsyncThunk complementary Guide

Alfred Boateng
6 min readJul 21, 2022

In this tutorial, we are going to build an application from scratch using the redux toolkit. We will fetch API data and display it on the screen. The application will also allow users to book rockets and join selected space missions. The whole application is available on github. Live link below

First, let’s create a React application using following the official React docs.

Create react application and test to see if everything works as expected

npx create-react-app app-name

Install the redux and redux toolkit

npm install @reduxjs/toolkit react-redux

Setup Redux Store

Create a new file src/app/store.js. Import the configureStore from Redux Toolkit.

  • Provide the Redux Store to React.

Update src/index.js. Replace the code with this. Remember that ReactDOM has been replaced with createRoot

Create a Redux Slice

The Redux toolkit recommends putting all your application logic inside the src/features folder. If you want to create a counter feature then your redux logic should be in src/features/counter/counterSlice.js. For missions the redux logic will be in src/features/mission/missionSlice.js and so on.

The first feature we want to create is for rockets. So let’s create a filesrc/features/rocket/rocketSlice.js. Import createSlice

Creating a slice requires a string name to identify the slice, an initial state value, and one or more reducer functions to define how the state can be updated. Once a slice is created, we can export the generated Redux action creators and the reducer function for the whole slice.

The basic structure of a slice look like this.

Let’s first look at what we want to do with this slice. We want to

- Fetch API data

- Render data on UI

- Add reserved status to some of the lists

- List all the data reserved

First, let’s fetch the API data. We will use axios and createAsyncThunk. Install Axios and update the rocketSlice.js

 npm install axios

You can read more about createAsyncThunk in the official docs.

Remember that we give it a name rockets/fetchRockets. This will be the action name. It will be referenced in the redux dev tools when we dispatch an action. We will not call it directly in the application.

The official docs recommend that we create the initials state like this

const initialState = {rockets: [],status: 'idle',error: null,};
  • rockets will be the array list we are expecting to receive from the API.
  • Fetching data from an API is a asynchronous task. status track the state of the async action.
  • If we encounter any errors we put them in the errors.

Reducers versus extra reducers

Inside the slice, we have reducers and extraReducers. Any difference?

Any async action will go into the extraReducers. If not put them in the reducers.

Let’s add this code to the extraReducers. For details about the extra reducers read the official docs

extraReducers: (builder) => {builder.addCase(fetchRockets.pending, (state) => {state.status = 'loading';}).addCase(fetchRockets.fulfilled, (state, action) => {state.status = 'succeeded';state.rockets = action.payload;}).addCase(fetchRockets.rejected, (state, action) => {state.status = 'failed';state.error = action.error.message;});},

As we’ve discussed earlier, extraReducers handle Async tasks. It take a builder, which comes with createSlice. Then for each of the Async task, we want to do something based on the state.

fetchRockets.pending check if the fetchRockets status is loading. If so we set the state of the rockets to loading.

fetchRockets.fulfilled Check if the data have been fetched successfully. If so we set the status to succeeded. Then we set th state.rocketst to payload from fetchRockets

fetchRockets.rejected check if fetchRockets encountered an error. If so we set the status as failed.

You can set the status to any name apart from loading, succeeded, or failed. But it should be something relevant because we will reference it later.

The next thing to do is export data from the state. There are different ways to do it. But I will export in the rocketSlice.js

export const selectAllRockets = (state) => state.rockets.rockets;
export const getRocketsStatus = (state) => state.rockets.status;
export const getRocketsError = (state) => state.rockets.error;

Finally the rocketSlice.js look like this

Add rocketSlice to store

Update src/App/store.js

use useSelector() to get the data from the redux store

Create a new file src/features/rocket/rocket.js.Add the following data to the file. This will be the file to handle the UI logic of this feature.

We want to fetch data based on the loading state. Import the rockets in the App.js file and render it on the screen.

Let’s use redux dev tools to look at what action has been dispatched

Data fetched using createAsyncThunk

If the data is not showing up in redux dev tools kindly go over the steps again. You also need to check your index.js file. Remember that ReactDom has been replaced with createRoot

Render data on the screen

let’s import the selectAllRockets defined in the rocketSlice.js and render it on the screen. Update the src/features/rocket/rocket.js file with this

Results

Dispatch Action

What if we want to perform some action and allow the state to respond. Let’s assume a user click a button to reserve some of these rockets.

Currently the API that we have does not have reserved status. So we can do it in the state. Update the function to fetch the data from the API so that each of the list items will have a default reserved status

export const fetchRockets = createAsyncThunk('rockets/fetchRockets',async () => {const response = await axios.get(ROCKET_URL);response.data.forEach((object) => {object.reserved = false;});return response.data;},);

Then we want to keep track of all the reserved rockets. Update the initial state to have an empty list of the reserved list

const initialState = {rockets: [],status: 'idle',error: null,reserved: [],};

Let’s define two actions reserveRocket to change the reserved state and myReservedRockets to show the list of rockets reserved.

Remember this does not require an async action. So let’s put them in the reducer. We want to export these two actions from the reducer. Update rocketSlice.js

Let’s now update the rocket.js file to dispatch an action and handle this action

Results

Profile Feature

What if we want to show all the rockets a user has reserved? I want to do this in a profile feature directory. This can be extended in the future.src/features/profile/profile.js

We need to add a react-router and update the routes. So that we are able to load the data whenever the page loads.

I hope you now understand clearly the flow of actions and data when using the redux toolkit. There is a lot. But the docs are getting too long. The app is available https://github.com/learnwithalfred/react-capstone-101

You can check the other features here, including

  • Toggle dark mode using redux
  • Missions feature
  • React router

I recommend you read the code. You will get an additional understanding of redux-toolkit flow.

Thanks for reading.

I am available for job opportunities. PortfolioLinkedInGitHubEmail

--

--

Alfred Boateng

Full-Stack Web Developer, Javascript, React.js, Node.js, Ruby on Rails, Team player