Hello, everyone π,
In this article, I describe how to create a custom UseFetch hook in React that can be reused as often as possible in other components to retrieve data from an API or from your local database file.
So let us get started...
First, we need to start our React app by typing the following command into the terminal.
npx create-react-app custom-fetch-hook
This will create a React application in a folder called custom-fetch-hook, which will contain all the files we need for this work. The folder structure will look like this image below.
The first thing I like to do when working with react is to clean up the src folder by deleting the entire folder and recreating my own src folder. In my new src folder, I create a new index.js and an App.js file. In the App.js file, we import our reusable custom useFetch hook.
Now we create another file in the src folder and name it useFetch.js. This is the custom hook file.
Then we use the rafce shortcut to create a functional component of react arrow. It will look like thisπ
import React from 'react'
const useFetch = () => {
return (
<div>
</div>
)
}
export default useFetch
Now we put our custom fetch code inside this file.
import {useEffect, useState } from 'react'
import axios from 'axios';
const useFetch = (url) => {
// create a states to load our fetched data, the data itself and also state for an error if there is one
const [data, setData] = useState([]) /// we set this to an array which is the array of data we will get back from the api
const [isLoading, setIsLoading] = useState(false) // We set this to a boolean because on page load it will appear and when data is fetched it will be set to falst back
const [error, setError] = useState('') //
useEffect(() => {
setIsLoading(true) // we set the false state to true so when the page loads we see 'loading...'
axios.get(url)
.then((response) => {
// setIsLoading(false) // set the 'loading...' so it disappears once the data is fetched.
setData(response.data)
})
.catch((err) => {
// setIsLoading(false) // set the 'loading...' so it disappears if there is error.
setError(err)
})
.finally(() => {
setIsLoading(false);
})
}, [url])
return {data, isLoading, error} // we return the data, isLoading and the error which we will destructure in out App component
}
export default useFetch
A brief explanation of the above code.
As expected, you should be familiar with the useState and useEffect hooks and how they work in React. Therefore, we automatically import these two hooks from React so we can use them in our code. Then we need to type npm install axios in our terminal to install it in our dependencies so we can use it for an API request.
Then, we delete the return value in useFetch up, because we do not return jsx in this file. There is one argument passed in the useFetch function, which is the URL we pass in it when we want to reach an API endpoint.
Afterwards, we create 3 different states. The first is displaying Loading... to the user before the data is retrieved from the API, and disappears once the data is retrieved. This state is initially set to false. The second state is the error state, to manage our errors in case something is wrong with the API endpoint we want to retrieve data from. This status is initially set to null. The last state is used to manage the data we get back from the API. We will use the https://fakestoreapi.com/ API. This state will be set to an array that we get back from the API endpoint.
then we create our useEffect function to retrieve the data from the above API using axios that we installed earlier. First, we setIsLoading to true so that when we start the useEffect function, we get the Loading... message. when we start the useEffect function. Then we make our axios request and pass the url argument we passed earlier in the useFetch function to axios.get(url). This will make the request to any URL endpoint and fetch the data from there. This will become even clearer when we test this function.
after the API call, we set the .then method to get our data back and set setData to = response.data. This means that our data is initially an array. When this useEffect function is executed, fill the array with the data we get back from the API.
Then we need to take care of the load state so that it stops once the data is fetched. There are two ways to do this: We add the .finally function after the error and setIsLoading to false or setIsLoading to false just before setting setData on response.data. Then we pass the url as a dependency, which means that as soon as the url changes, we want to call the useEffect function and request new data. After that, we need to return the three states we created earlier = data, isLoading, and error.
Then we can go into our App.js and make use of the useFetch function like this π
import React from 'react'
import useFetch from './useFetch'
const App = () => {
const {data, isLoading, error} = useFetch('https://fakestoreapi.com/products');
if(isLoading) return <div>Loading...</div>;
if (error) return <div>Could not fetch data from the resource </div>
console.log(data)
return (
<div>
{
data.map((item) => (
<div key={item.id}>
<h4>{item.title}</h4>
<p>{item.price}</p>
</div>
))
}
</div>
We import the function useFetch and pass in our real API endpoint, then destructure the data, isLoading and erorr. If the data is still being loaded from the endpoint, we return Loading.... When the process is complete, we map the data and display the desired jsx data. If the API is not correct or an error occurs, we get the return Could not retrieve data from resource.
Then we should have something like this π
And yes, we can now reuse this custom query in our other component to retrieve our data and not have to write the useEffect function every time.
I would appreciate it if you could take a moment and let me know what you think about my article! Any kind of feedback is appreciated.
Have fun learning!!!