A simple guide to consuming APIs with Redux (example tutorial)

A simple guide to consuming APIs with Redux (example tutorial)

Using state management in React to reduce the number of API calls you make to a server

Introduction to State management

One of the advantages of Javascript frameworks that use flux pattern is the ease with which data can be passed from a parent component to a child component and vice versa. However, there are situations where the same data needs to be used by more than one parent component in a React app.

Take for instance, a React app that makes a get request to an endpoint to fetch data from a server – If the data received as a response is to be used by more than one page of the React app, how do we make this work? State management.

With state management, we can create a store that will serve as the “single source of truth” for all the data being used by multiple pages in our react app. Without state management, the developer would need to make independent API calls in each component that requires the data from the API and this approach is not ideal as it might result in:

  1. Slow response time as each page would need to re-fetch the data for each page visit
  2. Overloading of servers as they would be fulfilling multiple requests at the same time.

In this article, we’ll be building a react app that uses Redux to fetch user data from the Randomuser API, save the data in the store and makes it available to all components and pages within the react app.

Let’s get hacking!

Step 1: Create a React app

Open your command terminal, change to any directory of your choice, use the following command to create a new React app and name it redux-tutorial

npm create-react-app reduxtutorial

Now, cd into the newly created app in the code editor of your choosing. In this tutorial, I’ll be using VS Code.

Step 2: Install all the packages we need

Next, we will be installing all the packages we need to create and test our redux store:

1) react-redux and redux/toolkit packages to install the redux store in our React app 2) axios for API calls to the endpoint we would be making a GET request to for this tutorial 3) react-router and react-router-dom to create multiple routes in our React app to test if the state is indeed available in all routes and components.

To install all these required packages, enter the code below:

 npm i @reduxjs/toolkit react-redux react-router react-router-dom axios

Afterwards, start your react app with: npm run start

Step 3: Create routes in our React app

Now that we have installed all required packages, let us create the two routes we would be using for the purpose of this tutorial:

  • Create a pages folder in your src folder and create two files within it: Home.js and Users.js

  • Afterwards, copy the following lines of code below into your App.js file

import './App.css';
import Home from './pages/Home';
import { BrowserRouter,Routes,Route } from 'react-router-dom';
import Users from "./pages/Users"

function App() {
  return (
    <BrowserRouter>
    <Routes>
    <Route path="/" element={<Home/>}/>
    <Route path="/users" element={<Users />} />
    </Routes>
    </BrowserRouter>
  );
}

export default App;

Step 4: Create a store in your app at src/store/store.js

Create a store with the following lines of code:

import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
  reducer: {
    users:{}
  }
})

Step 5: Provide the Redux store to react so all the components can access it

After you have created your redux store, we need to use a Provider from the React Redux package to make the store available to all our routes and components. To do this, navigate to your index.js file and enter the following lines of code:


import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {store } from "./store/store"
import { Provider } from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
  <React.StrictMode>
    <App />
  </React.StrictMode>
  </Provider>
);
reportWebVitals();

Step 6: Create a Redux state Slice

As state values in redux cannot be altered directly within the component, we need to create a State slice that would perform our state changes on our behalf when fired as a function in a react component. As the data we want to store in our state comes from an asynchronous call to an API endpoint, we would be using axios to make the get request and then createAsyncThunk to enable the asynchronous function to fire and store a promise in the state, pending the time when the data arrives.

The initialState part of the Redux slice contains the initial state of our store. As we are making an asynchronous call, we would be adding a loading state which will change from false to true and true to false depending on whether data has been fetched successfully or not. We would also be using extraReducers to monitor our state change from pending to fulfilled to failed.

To do this, create a new file called user.js in src/store folder and enter the following lines of code.


import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

const initialState = {
  value: [],
  loading: false,
};

export const getUsers = createAsyncThunk("users/getUsers", async () => {
  try {
    const response = await axios({
      method: "GET",
      url: "https://randomuser.me/api/?gender=male&results=3",
      headers: {
        ContentType: "application/json",
      },
    });
    return response.data.results;
  } catch (error) {
    return error;
  }
});

export const usersSlice = createSlice({
  name: "user",
  initialState,
  extraReducers: {
    [getUsers.pending]: (state, action) => {
      state.loading = true;
    },
    [getUsers.fulfilled]: (state, action) => {
      state.loading = false;
      state.value = action.payload;
    },
    [getUsers.rejected]: (state, action) => [(state.loading = "failed")],
  },
});

export default usersSlice.reducer;

Step 7: Add Redux state slice to the store

Now that we have successfully written the logic to fetch our user data from the API, we need to connect our state slice to the store with the code below:

import { configureStore } from '@reduxjs/toolkit'
import user from './user'

export const store = configureStore({
  reducer: {
    users:user
  }
})

Step 8: Dispatch and Fetch Data from the Store in your React Component

Now, we are ready to fire a function within our react component that would fetch the data from the API, store it in the Redux store and make it available across every route. We would be using the useSelector and useDispatch package from Redux to do this.

Add the following lines of code to the Home.js file created earlier:

import React,{useEffect} from 'react'
import { useSelector,useDispatch } from 'react-redux'
import { getUsers } from "./../store/user"
import { useNavigate } from 'react-router'

function Home() {
  const users = useSelector((state) => state.users.value)
  const dispatch = useDispatch()
  const history = useNavigate()

  useEffect(()=>{
    dispatch(getUsers())
  },[dispatch])

  const gotonextpage = () =>{
    history('/users')
  }

  return (
    <div>
      <div>
        {/* {count} */}
        {users.map((user,i)=>(
            <div key={i}>
                <p>{user.name.title} {user.name.first} {user.name.last}</p>
                <img src={user.picture.large} alt="img"/>
            </div>
        ))}
        <button onClick={()=>gotonextpage()}>Go to users</button>
      </div>
    </div>
  )
}

export default Home

At this stage, your react app should look like this:

Capture2.PNG

Step 9: Check for the state in another Route

By now, you should be seeing a list of 3 names and images on your home screen. This data is being fetched from the API and stored in redux. To confirm that the data is indeed available to other routes, let us add the following lines of code to the users.js file created in Step 3

In /src/pages/Users.js file

import React from 'react'
import { useSelector } from "react-redux"

function User() {
    const users = useSelector((state) => state.counter.value)
  return (
    <div>
        {users.map((user,i)=>(
            <div key={i}>
                <p>{user.name.title} {user.name.first} {user.name.last}</p>
                <img src={user.picture.large} alt="img"/>
            </div>
        ))}
    </div>
  )
}

export default User

[BONUS] Step 10: Install the Redux Devtools extension in Chrome

To properly track all your dispatches and state management in Redux, you can install the Redux Devtool extension to view changes being made to your state in real-time. Here is a screenshot of what the state for the tutorial we just did looks like:

Capture.PNG

Conclusion

In this tutorial, we were able to successfully make GET requests to an API, store the data fetched from the response within our store and make this data available to all the routes and components in our React app. You can view the repo for the code here and meddle with it as much as you want.

Happy Hacking ✌