React - Making HTTP Requests using Fetch and useEffect
Making HTTP requests are important in any web application as it provides us ways to store, update, delete or retrieve data stored in database.
There are various libraries such as axios are available to do this, but today we will use Fetch which is provided by JavaScript.
A simple fetch request will take one parameter i.e. URL. In case you want to setup header, method type etc., it can be done by using providing an object alongside URL.
Fetch return promise, which provides us a guarantee that it will return response, either success or failure.
The response object does not directly contain actual JSON object, instead it returns an representation of the HTTP response. To extract the actual JSON object, we need to use json() method, which in turn returns another promise which will have actual JSON object.
In react, the best way to make any AJAX request is useEffect. As we have setup our Apache server already, lets put a books.json there and fetch it using the Fetch method.
We can use fetch() in 2 ways:
- Using promises
- Using async-await
Using Promises
JavaScript
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const FetchAPIDemo = () => {
const [url, setUrl] = useState("http://localhost:80/books.json");
const [clickCount, setClickCount] = useState(0);
const [books, setBooks] = useState([]);
useEffect(() => {
console.log("Use Effect for Books API call is called..");
fetch(url)
.then((response) => response.json())
.then((data) => {
setBooks(data);
});
}, [url]);
const changeAPIUrl = () => {
setUrl("http://YOUR_IP_ADDRESS:80/books.json");
};
return (
<React.Fragment>
<div className="App">
<header className="App-header">
<p>Current counter value is {clickCount}</p>
{books.length > 0 ? (
<div className="add-column-margin">
<div
id="myCarousel"
className="carousel slide"
data-ride="carousel"
>
<ol className="carousel-indicators">
{books.map((book, index) => {
return (
<li
key={index}
data-target="#myCarousel"
data-slide-to={index}
className={index === 0 ? "active" : ""}
></li>
);
})}
</ol>
<div className="carousel-inner">
{books.map((book, index) => {
return (
<div
key={index}
className={
index === 0 ? "carousel-item active" : "carousel-item"
}
>
<img
className="d-block w-100"
src={book.coverImage}
alt="First slide"
></img>
<div className="carousel-caption d-none d-md-block">
<h5
style={{
color: "white",
backgroundColor: "rgba(0, 0, 0, 0.6)",
}}
>
{book.title}
</h5>
</div>
</div>
);
})}
</div>
<a
className="carousel-control-prev"
href="#myCarousel"
role="button"
data-slide="prev"
>
<span
className="carousel-control-prev-icon"
aria-hidden="true"
></span>
<span className="sr-only">Previous</span>
</a>
<a
className="carousel-control-next"
href="#myCarousel"
role="button"
data-slide="next"
>
<span
className="carousel-control-next-icon"
aria-hidden="true"
></span>
<span className="sr-only">Next</span>
</a>
</div>
<button
className="btn btn-primary mx-auto float-left"
onClick={() => {
setClickCount((prevClickCount) => prevClickCount + 1);
}}
>
Increment Count
</button>
<button
className="btn btn-primary mx-auto float-right"
onClick={changeAPIUrl}
>
Change URL
</button>
</div>
) : (
<p>Loading...</p>
)}
</header>
</div>
</React.Fragment>
);
};
export default FetchAPIDemo;
Notice that we are changing the URL from http://localhost:80/books.json to http://YOUR_IP_ADDRESS:80/books.json, on click of the button which essentially pointing to the same books.json.
Output
When component renders for the first time
- Notice that useEffect is called, it has fetched the data using http://localhost:80/books.json
When incrementing the count
- When we increment the count, useEffect is not called.
Changing the URL
- Notice that when we change the URL, its actually pointing to the same books.json but instead of localhost, I have used MY_IP_ADDRESS, which technically resolved to the same resource.
- This also shows how we can use dependencies with useEffect, where change in url can create a side-effect.
- Also note that in case you are not passing any dependency, either empty array for one time run or any other value, as per our implemented logic will be in a infinite loop, as useEffect will be called every time re-render happens and useEffect will make that component re-render by updating state!
Async-Await
Fetch with async-await works asynchronously, and also returns promise but it reduces the boilerplate code required with traditional promise based calls, promotes cleaner code and reduces need to explicitly configure promise chains.
use of await keyword is permitted only when function is declared with async.
Only change is we use async before the callback function and then await for the response.
useEffect(async () => {
console.log("Use Effect for Books API call is called..");
const response = await fetch(url);
const data = await response.json();
setBooks(data);
}, [url]);
- There won't be any change in the response of the API.
- Fetch returns a promise, so it awaits until its resolved.
Comments
Post a Comment