DEV Community

Cover image for A Complete Guide To API Calls With React And Axios
Uma Chisom Augustin
Uma Chisom Augustin

Posted on

A Complete Guide To API Calls With React And Axios

In this post, we are to be looking at how to use Axios in fetching data, manipulating it, and displaying it on your page with filtering functionality. We are also going to learn how to use the map, filter, and include method. In addition to that, you will learn how to create a simple loader to handle the loading state of the fetched data from the API endpoint.

Setting up the project

The first thing we need to do is set up the project with the create-react-app command terminal:

npx create-react-app project-name
Enter fullscreen mode Exit fullscreen mode

Next thing is to open up the project directory through the terminal window, then input npm install axios to install Axios for the project locally.

Choose Target API

To do this, we are going to be using the Random User Generator API to fetch random user information, which we are going to use in our application. The next step is to add the Axios module to the application by importing it into our App.js file.

import axios from 'axios'
Enter fullscreen mode Exit fullscreen mode

The next thing we are going to do is to fetch ten different users, and we are going to need only the name, last name, and a unique ID, which is required for React when creating lists of elements. This will also make the call more specific, for example, the nationality option.

Check out the API URL that we will make the call for below:

https://randomuser.me/api/?results=10&inc=name,registered&nat=fr 
Enter fullscreen mode Exit fullscreen mode

Note: i did not use the id option that was provided in the API because sometimes it returns null for some users. I made sure that there will be a unique value for each user, by including the registered option in the API.

Copy and paste it on your browser, you will see the returned data in JSON format.

The next thing is to make an API call through Axios.

Creating the App States

The first thing we are going to do is create the states using the useState hook from the React, so that we can be able to store the fetched data.

Inside our App component, next thing is to import the useState hook from React and then create the states as seen below.

import React, { useState } from "react";
import axios from "axios";

const App = () => {
  const [users, setUsers] = useState([]);
  const [store, setStore] = useState([]);

  return (
    <div>

    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

You can see the users and store states. One will be used for the purpose of filtering, and won’t be edited, while the other one will hold the filter results that will hold the filter results that will be shown in the DOM.

Fetch Data With Axios

Next thing is to create a getUsers function that will handle the fetching of data. In this function, we are going to use axios to fetch our data from the API using get method.

For us to display our fetched data when the page loads, we will have to import a React hook called useEffect and call the getUsers function inside it.

The useEffect is responsible for managing the side effects in functional components, and it is similar to the componentDidMount() lifecycle hook that is usually used in React class-based components. This hook accepts an empty array as a second argument for the purpose of side-effects cleanups. What you should do now is update the code in the App component, so that we check for the response data in the console, as shown below.

import React, { useState, useEffect } from "react";

const App = () => {
  const [users, setUsers] = useState([]);
  const [store, setStore] = useState([]);

  const getUsers = () => {
    axios.get("https://randomuser.me/api/?results=10&inc=name,registered&nat=fr")
      .then(response => console.log(response))
  };

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

  return (
    <div>

    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Check the console, you will see an object output. Open the object, and you will see another object inside named data , inside the data, you will see an array known as results. If you want to return a specific value from the results, you can update the axios.get call as seen below.

axios.get("https://randomuser.me/api/?results=10&inc=name,registered&nat=fr")
  .then(response => console.log(response.data.results[0].name.first))
Enter fullscreen mode Exit fullscreen mode

What we did here is to log the name of the first value inside the results array.

Process the Result Data

What we are going to do next is to use the built-in map method for JavaScript in order to iterate through each element inside the array and create a new array of JavaScript Objects with a new structure.

As shown below, update your`getUsers function:

const getUsers = () => {
  axios
    .get("https://randomuser.me/api/?results=10&inc=name,registered&nat=fr")
    .then((response) => {
      const newData = response.data.results.map((result) => ({
        name: `${result.name.first} ${result.name.last}`,
        id: result.registered
      }));
      setUsers(newData);
      setStore(newData);
    })
    .catch((error) => {
      console.log(error);
    });
Enter fullscreen mode Exit fullscreen mode

What we did in the code above is that we created a variable called newData. It stores the results by looking through the response.data.results array with the map method. Between the map callback, we are going to reference each element of the array as result (notice the singular/plural difference). Also, when we use the key-value pair of each object inside the array, we create another object with name and id key-value pairs.

Normally, if you go and check the result of the API call in your browser, you will notice that there are first and last key-value pairs inside the name object, but there is no no key-value pair for full name. From the code is showed you above, i was able to combine the first and last names to create a full name inside the JavaScript object.

Note: the JSON and JavaScript objects are different things, even though they work pretty much the same way.

Populate Data Stores With Filtering

The idea of filtering is not difficult at all. We have our store state, which keeps the original data always without changing. By using the filter function on this state, we only get the matching elements, then we assign them to the users state.

const filteredData = store.filter((item) => (
    item.name.toLowerCase().includes(event.target.value.toLowerCase()))
Enter fullscreen mode Exit fullscreen mode

The filter method requires a function as an argument, a function that will run for each element in the array. Here, we are going to be referring to each element inside the array as item. Then, the next thing is to take the name key of each item and convert it to lower case so that we can make our filtering functionality case insensitive.

In the end, the filter method returns the matching elements. So, we just simply take these elements and store them in the setUsers state.

Next is to update the App component with the final version of the function we created.

const filterNames = (event) => {
   const filteredData = store.filter((item) =>
     item.name.toLowerCase().includes(event.target.value.toLowerCase())
   );
   setUsers(filteredData);
 };
Enter fullscreen mode Exit fullscreen mode

Creating the Components

We can actually put everything inside the App component for this small example, but let’s take advantage of React and make small functional components.

Let us add some components to the app. The first thing is to import the components from separate JavaScript files, which we will define soon.

import Lists from "./components/Lists";
import SearchBar from "./components/SearchBar";
Enter fullscreen mode Exit fullscreen mode

Next thing is to update our App components return statement to make use of these components.

return (
  <div className="Card">
      <div className="header">NAME LIST</div>
      <SearchBar searchFunction={filterNames} />
      <Lists usernames={users} />
  </div>
);
Enter fullscreen mode Exit fullscreen mode

If you notice, there is the searchFunction prop for the SearchBar component and the usernames prop for the Lists component.

Note: we are going to be using users state instead of the store state to show the data. This is because the users state contains the filtered results.

**SearchBar** Component
This component only takes the filterNames function as a prop and calls this function when the input field changes. Put the code below on components/SearchBar.Js:

import React from 'react';

const SearchBar = ({ searchFunction}) => {
  return (
    <div>
        <input className="searchBar" type='search' onChange={searchFunction} />
    </div>
  )
};

export default SearchBar;
Enter fullscreen mode Exit fullscreen mode

List Component
This List Component lists the names of the users. Put it into the components/List.js:

import React from 'react';

const Lists = ({ usernames }) => {
  return (
      <div>
          <ul>
              {usernames.map(username => (
                  <li key={username.id}>{username.name}</li>
              ))}
          </ul>
      </div>
  )
};

export default Lists;
Enter fullscreen mode Exit fullscreen mode

Again, we used the map method to get each item in the array and create a <li> item out of it.

Note: when ****you use map to create a list of items, you should use a key so that React will keep track of each list item.

Track Loading State

To create a loading state, we have to use useState hook to show when the data is yet to be fetched.

const [loading, setLoading] = useState(false);
Enter fullscreen mode Exit fullscreen mode

The next step is to update the loading state in our data fetch method.

const getUsers = () => {
  axios.get("https://randomuser.me/api/?results=10&inc=name,registered&nat=fr")
    .then((response) => {
      const newData = response.data.results.map((result) => ({
        name: `${result.name.first} ${result.name.first}`,
        id: result.registered,
      }));
      setLoading(true);
      setUsers(newData);
      setStore(newData);
    })
    .catch((error) => {
      console.log(error);
    });
};
Enter fullscreen mode Exit fullscreen mode

What we did here is create a loading state and set it to false initially. We then set this state to true while fetching the data with the setLoading state. Finally, we are going to return statement to render the loading state as shown below:

return (
  <>
    {loading ? (
      <div className="Card">
        <div className="header">NAME LIST</div>
        <SearchBar searchFunction={filterNames} />
        <Lists users={users} />
      </div>
    ) : (
      <div className="loader"></div>
    )}
  </>
);
Enter fullscreen mode Exit fullscreen mode

We used the JavaScript ternary operator to render the SearchBar and Lists components when the loading state is false and then rendered a loader when the loading state is true. We also created a simple loader to display to display the loading state in the interface.

Style With CSS

This is the CSS file specific to this example:

body,
html {
-webkit-font-smoothing: antialiased;
margin: 0;
padding: 0;
font-family: "Raleway", sans-serif;
-webkit-text-size-adjust: 100%;
}

body {
display: flex;
justify-content: center;
font-size: 1rem/16;
margin-top: 50px;
}

li,
ul {
list-style: none;
margin: 0;
padding: 0;
}

ul {
margin-top: 10px;
}

li {
font-size: 0.8rem;
margin-bottom: 8px;
text-align: center;
color: #959595;
}

li:last-of-type {
margin-bottom: 50px;
}

.Card {
font-size: 1.5rem;
font-weight: bold;
display: flex;
flex-direction: column;
align-items: center;
width: 200px;
border-radius: 10px;
background-color: white;
box-shadow: 0 5px 3px 0 #ebebeb;
}

.header {
position: relative;
font-size: 20px;
margin: 12px 0;
color: #575757;
}

.header::after {
content: "";
position: absolute;
left: -50%;
bottom: -10px;
width: 200%;
height: 1px;
background-color: #f1f1f1;
}

.searchBar {
text-align: center;
margin: 5px 0;
border: 1px solid add8e6;
height: 20px;
color: #575757;
border-radius: 3px;
}

.searchBar:focus {
outline-width: 0;
}

.searchBar::placeholder {
color: #dadada;
}

.loader {
border: 15px solid #ccc;
border-top: 15px solid #add8e6;
border-bottom: 15px solid #add8e6;
border-radius: 50%;
width: 80px;
height: 80px;
animation: rotate 2s linear infinite;
}

@keyframes rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

Enter fullscreen mode Exit fullscreen mode




Conclusion

In this tutorial, we used the Random User Generator API as the source of random user data. We then fetched the data from an API endpoint and restructured the results inside a new JavaScript object with the map method.

The next thing we did was to create a filtering function with the filter and includes methods. Then finally, we created two different components and conditionally rendered our components with a loading state when the data is not fetched yet.

Top comments (1)

Collapse
 
svgatorapp profile image
SVGator

Very thorough walk-through! Great work