0% completed
When fetching data, errors can happen, like network issues or invalid URLs. You can handle these errors with .catch()
or a try-catch
block.
Example:
useEffect(() => { const fetchData = async () => { try { const response = await fetch("https://api.example.com/fruits"); if (!response.ok) throw new Error("Network response was not ok"); const data = await response.json(); setFruits(data); setLoading(false); } catch (error) { console.error("Error fetching data:", error); } }; fetchData(); }, []);
In this useEffect
hook example:
fetchData
fetches data from a URL ("https://api.example.com/fruits").fetchData
, it sends a request to the API and checks if the response is successful.setFruits(data)
. It also sets setLoading(false)
to indicate the loading process is complete.fetchData
function is called immediately after being defined.[]
) ensures this effect runs only once when the component mounts.Here’s a simple example of fetching data from an API using useEffect
:
Example:
import React, { useState, useEffect } from "react"; const FruitList = () => { const [fruits, setFruits] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { fetch("https://api.example.com/fruits") .then((response) => response.json()) .then((data) => { setFruits(data); setLoading(false); }) .catch((error) => console.error("Error fetching fruits:", error)); }, []); if (loading) return <p>Loading...</p>; return ( <ul> {fruits.map((fruit) => ( <li key={fruit.id}>{fruit.name}</li> ))} </ul> ); }; export default FruitList;
Breakdown of the Code:
State Management
fruits
holds the fetched data.loading
tracks whether the data is still being fetched.Fetching Data
fetch
function retrieves data from the API..then()
methods handle the response.Conditional Rendering
Error Handling
.catch()
method handles errors in a Promise chain by logging a custom error message and the error object (e.g., with console.error
), ensuring efficient error management.Sometimes, effects like timers or subscriptions need to be cleaned up to prevent memory leaks. useEffect
lets you return a cleanup function that runs when the component unmounts.
Example:
useEffect(() => { const timer = setInterval(() => { console.log("Timer running..."); }, 1000); return () => clearInterval(timer); // Cleanup }, []);
For data fetching, you might clean up ongoing requests using the AbortController
.
Race conditions happen when multiple fetch requests overlap, and the app uses outdated data. To prevent this, you can use the Abortcontroller to cancel the previous request when a new one starts.
Example:
useEffect(() => { const controller = new AbortController(); const signal = controller.signal; const fetchData = async () => { try { const response = await fetch("https://api.example.com/fruits", { signal }); const data = await response.json(); setFruits(data); } catch (error) { if (error.name === "AbortError") { console.log("Fetch aborted"); } else { console.error("Error fetching data:", error); } } }; fetchData(); return () => controller.abort(); // Cancel the request }, []);
.....
.....
.....