How to Make API Calls with Redux Toolkit

·

4 min read

How to Make API Calls with Redux Toolkit

Introduction

Redux helps manage the state in React, and Redux Toolkit is a setup that makes it easier to use Redux with React. In this blog post, we'll explore how to fetch data using Redux Thunk, a part of React Redux, along with Axios, which is a React library.

To begin, let's Understand the flow of React Redux from the below image that explores various features such as reducers, Redux store, event dispatch, and handler functions. This will provide us with a basic understanding of the components that Redux Toolkit simplifies.

Installation & Setup

First, Create a new React app and navigate into the app

npx create-react-app react-axios-demo
cd react-axios-demo

Install the necessary dependencies for the project.

npm install axios react-redux @reduxjs/toolkit

Fetching APIs Using Axios and Redux thunk

We'll construct the code following the flowchart explanation of React Redux outlined above, making the process more straightforward.

Building Reducers and slices

As indicated in the flowchart, creating a Redux store is essential to store states, and reducers are necessary to update these states. Let's proceed to build these components.

  • Store.js - The Redux store is set up using the configureStore method from the Redux Toolkit. This method takes reducers as inputs. Since we're using the Redux Toolkit, these reducers come in the form of slices, placed in different locations for simplicity.

      import { configureStore } from "@reduxjs/toolkit";
      import todoReducer from "./slice/todo.js";
    
      export const store = configureStore({
          reducer: {
              todo: todoReducer,
          }
      });
    
  • Slice/todo.js -It is a file in the Slice folder, where we provide reducers used to update the state in the store based on the actions dispatched from the event handler via the Redux store.

    Here, the createSlice method accepts arguments such as name, indicating the name of the reducer. The initialState parameter reduces the need for us to manually assign states in various edge cases. Additionally, extraReducers comes with built-in methods that we can use to perform actions at different stages of the API fetching process.

    We also utilize the axios library to fetch APIs using a specific HTTP request, 'get', which extracts the data from the URL. Axios provides out-of-the-box features for handling APIs

      import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
      import axios from "axios";
    
      // Action
      export const fetchTodos = createAsyncThunk('fetchTodos', async () => {
          const response = await axios.get('https://jsonplaceholder.typicode.com/todos');
          return response.data;
      })
    
      // Slice
      const todoSlice = createSlice({
          name: 'todo',
          initialState: {
              isLoading: false,
              data: null,
              isError: false,
          },
          extraReducers: (builder) => {
              // API Fetching (GET) is pending
              builder.addCase(fetchTodos.pending, (state, action) => {
                  state.isLoading = true;
              });
              // API Request fulfilled (Success)
              builder.addCase(fetchTodos.fulfilled, (state, action) => {
                  state.isLoading = false;
                  state.data = action.payload;
              });
              // Request is rejected
              builder.addCase(fetchTodos.rejected, (state, action) => {
                  state.isError = true;
                  console.error("Error", action.error);
              });
          }
      })
    
      const todoReducer = todoSlice.reducer;
    
      export default todoReducer;
    

Building UI

  • App.jsx - We will fetch data from the API when the onClick() function is triggered. Subsequently, we display the retrieved data on the webpage, and the code incorporates styling using Tailwind CSS.

      import React from 'react';
      import { useDispatch, useSelector } from 'react-redux';
      import { fetchTodos } from './redux/slice/todo';
    
      const App = () => {
          const dispatch = useDispatch();
          const state = useSelector((state) => state);
    
          if (state.todo.isLoading) {
              return (
                  <div className=" flex items-center justify-center h-screen">
                      <h1 className="text-4xl font-bold">Loading....</h1>
                  </div>
              );
          }
    
          return (
              <div className="max-w-md mx-auto p-4">
                  <button
                      onClick={(e) => dispatch(fetchTodos())}
                      className="bg-blue-500 text-white font-bold py-2 px-4 rounded mb-4">
                      Fetch Data
                  </button>
    
                  {state.todo.data && (
                      <ul>
                          {state.todo.data.map((e) => (
                              <li key={e.id} className="mb-2 p-2 bg-gray-100 rounded">
                                  {e.title}
                              </li>
                          ))}
                      </ul>
                  )}
              </div>
          );
      };
    
      export default App;
    
  • Index.js - This is the root file that React will render on the webpage. Here, we provide the store as props to the Provider, which wraps the App.jsx file

      import React from "react";
      import ReactDOM from "react-dom/client";
      import App from "./App";
      import { Provider } from "react-redux";
      import { store } from "./redux/store";
    
      const root = ReactDOM.createRoot(document.getElementById("root"));
      root.render(
          <React.StrictMode>
              <Provider store={store}>
                  <App />
              </Provider>
          </React.StrictMode>
      );
    

Rendering & Testing

In this process, we utilize an extension called Redux Dev Tools to inspect the states in the context of React Redux. This extension provides us with convenient tools right from the beginning for testing React Redux states.

To see it in action, run the following command:

npm start

Here, the image below displays the states in Dev Tools and the webpage before fetching data from the API. It illustrates the states before data retrieval in raw format, where the default states are set to false and data to null.

Now, after fetching data and moving past the loading stage, the Dev Tools display the states and the retrieved data. The data (todos) is subsequently rendered on the webpage.

Final thoughts

In conclusion, the Redux Toolkit simplifies our tasks and proves to be very useful for fetching APIs. Additionally, we make use of the Axios library to make API fetching even easier.

Resources

  1. Redux toolkit Official Documentation: https://redux-toolkit.js.org/introduction/getting-started

  2. Axios React GitHub Repository: https://github.com/axios/axios