A Complete Guide To API Calls With React And Axios
Published: 2022-03-21 16:11:11



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

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](https://www.randomuser.me/) 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'

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 

**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;

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;

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))

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);
        });

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()))

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);
     };


## 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";

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>
    );

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;

**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;

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);

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);
        });
    };

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>
        )}
      </>
    );

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); }
    }


## Conclusion

In this tutorial, we used the [Random User Generator API](https://www.randomuser.me/) 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.