useEffect(() => {
fetch("http://localhost:3000/places")
.then((response) => response.json())
.then((responseData) => setAvailablePlaces(responseData.places));
}, []);
- Basic
fetch
nested with.then()
callbacks. - This approach works but can become hard to read and maintain.
const [availablePlaces, setAvailablePlaces] = useState([]);
const [isFetchingData, setIsFetchingData] = useState(false);
useEffect(() => {
async function fetchPlaces() {
setIsFetchingData(true);
const response = await fetch("http://localhost:3000/places");
const responseData = await response.json();
setAvailablePlaces(responseData.places);
setIsFetchingData(false);
}
fetchPlaces();
}, []);
- Replaced
.then()
with anasync function
. - Added a loading state (
isFetchingData
) to show feedback to the user while fetching.
Note
An async function declaration creates an AsyncFunction
object.
Each time when an async function is called, it returns a new Promise
which will be resolved with the value returned by the async function, or rejected with an exception uncaught within the async function.
const [availablePlaces, setAvailablePlaces] = useState([]);
const [isFetchingData, setIsFetchingData] = useState(false);
const [error, setError] = useState();
useEffect(() => {
async function fetchPlaces() {
try {
setIsFetchingData(true);
const response = await fetch("http://localhost:3000/places");
const responseData = await response.json();
if (!response.ok) {
throw new Error("Fetching data error :(");
}
setAvailablePlaces(responseData.places);
} catch (error) {
setError(
error.message ||
"Could not fetch the places data, please try again later."
);
}
setIsFetchingData(false);
}
fetchPlaces();
}, []);
- Added error handling using a
try/catch
block. - Included an error state to manage and display errors.
Moved the HTTP request logic to a standalone utility function http.js
for cleaner and more reusable code.
export async function fetchAvailablePlaces() {
const response = await fetch("http://localhost:3000/places");
const responseData = await response.json();
if (!response.ok) {
throw new Error("Error fetching places data.");
}
return responseData.places;
}
//final example code
import { fetchAvailablePlaces } from "../http.js";
async function fetchPlaces() {
try {
setIsFetchingData(true);
const places = await fetchAvailablePlaces();
setAvailablePlaces(places);
} catch (error) {
setError(error.message || "Failed to fetch places.");
}
setIsFetchingData(false);
}
By default, fetch uses the GET method
. If you want to use a different HTTP method
, you need to provide an options object with specific properties such as method
, body
, and headers
.
This function sends an HTTP PUT
request to update user places on the server.
export async function updateUserPlaces(places) {
const response = await fetch("http://localhost:3000/user-places", {
method: "PUT", // Specify the HTTP method
body: JSON.stringify({ places }), // Convert JS object to JSON format
headers: {
"Content-Type": "application/json", // Inform the server about the data type
},
});
const responseData = await response.json(); // Parse the response body as JSON
if (!response.ok) {
throw new Error("Updating user places went wrong :("); // Handle errors
}
return responseData.message; // Return a success message
}
Common HTTP Methods π
GET
β‘οΈ Retrieve data from the server
POST
β‘οΈ Send new data to the server
PUT
β‘οΈ Update existing data on the server
DELETE
β‘οΈ Remove data from the server
PATCH
β‘οΈ Partially update data
body: JSON.stringify({ places })
JSON.stringify()
converts a JavaScript object into a JSON-formatted string because HTTP requests require plain text (not raw JS objects).- You must pass an
object
with key-value pairs (e.g., { places: [...] }) so the server can properly identify and handle the data.
headers: { "Content-Type": "application/json" }
- The
headers
property defines additional information sent with the request. Content-Type: application/json
tells the server that the body contains JSON-formatted data, ensuring it is parsed correctly.
response.json()
- The
.json()
method reads the server's response body and converts it into a JavaScript object. - This is necessary because fetch returns a
stream
by default, and you need to "decode" it into usable data.
πΈ This project is a practice exercise I learned from the Academind's React Course πΈ