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 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 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)
Very thorough walk-through! Great work