Fetching Data from APIs
# Fetching Data from APIs
1. Introduction
React only handles the User Interface (the frontend). It does not have a database. To get real data—like a list of users, the current weather, or a product catalog—your React app must communicate over the internet with a backend server using an API (Application Programming Interface). In this chapter, we will learn how to fetch data using the nativefetch() API and display it using State and Effects.
2. Learning Objectives
By the end of this chapter, you will be able to:-
Use the JavaScript
fetch()API inside a React component.
- Manage "Loading", "Error", and "Success" states.
- Parse JSON data and store it in React State.
- Understand the basics of Axios (a popular alternative to fetch).
3. Beginner-Friendly Explanations
What is an API?
An API is like a waiter in a restaurant. You (the frontend React app) ask the waiter (the API) for a specific meal (data). The waiter goes to the kitchen (the backend database), gets the meal, and brings it back to your table. The standard format for data exchange on the web is JSON (JavaScript Object Notation), which looks exactly like standard JavaScript objects and arrays.The Standard Data Fetching Pattern
Whenever you fetch data in React, you generally need three state variables:-
1.
data: To hold the actual data once it arrives.
-
2.
isLoading: A boolean to show a spinner while waiting for the network.
-
3.
error: A string to show an error message if the server crashes or the internet drops.
4. Syntax Explanation
Step 1: Basic Fetch with useEffect
We must place our fetch logic insideuseEffect with an empty dependency array [] so it only runs once when the component loads. We will use modern async/await syntax.
```jsx id="ch19_ex1" import { useState, useEffect } from 'react';
function UserList() { // 1. Setup the three core states const [users, setUsers] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { // 2. Define an async function const fetchData = async () => { try { // Request data from a public testing API const response = await fetch('https://jsonplaceholder.typicode.com/users'); // Check if the response is OK (status 200) if (!response.ok) throw new Error("Network response was not ok"); // Convert the response to JSON const data = await response.json(); // Save to state setUsers(data); } catch (err) { setError(err.message); } finally { // Stop loading regardless of success or failure setIsLoading(false); } };
// 3. Call the function fetchData(); }, []); // Empty array! Run once.
// 4. Conditional Rendering based on state if (isLoading) return <p>Loading users...</p>; if (error) return <p>Error: {error}</p>;
// 5. Render Data return ( <ul> {users.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> ); }
jsx id="ch19_ex2" import axios from 'axios'; // Inside useEffect: const fetchData = async () => { try { // Axios automatically parses JSON! const response = await axios.get('https://api.example.com/data'); setData(response.data); } catch (err) { setError(err.message); } };
jsx id="ch19proj1" // Example React component import React, { useState, useEffect } from 'react';
export default function WeatherWidget() { const [weather, setWeather] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState("");
// We are using a free geocoding API for demonstration const fetchWeather = async () => { setLoading(true); setError(""); try { // Free public API for testing const res = await fetch('https://api.open-meteo.com/v1/forecast?latitude=40.71&longitude=-74.00¤tweather=true'); if (!res.ok) throw new Error("Weather service unavailable"); const data = await res.json(); setWeather(data.current_weather); } catch (err) { setError(err.message); } finally { setLoading(false); } };
useEffect(() => { fetchWeather(); }, []);
return ( <div className="flex justify-center items-center p-10 bg-slate-100 min-h-[300px]"> <div className="bg-white p-8 rounded-3xl shadow-xl w-80 text-center relative overflow-hidden"> {/* Loading State */} {loading && ( <div className="flex flex-col items-center animate-pulse"> <div className="w-16 h-16 bg-slate-200 rounded-full mb-4"></div> <div className="h-4 w-24 bg-slate-200 rounded"></div> </div> )}
{/* Error State */} {error && ( <div className="text-red-500 font-bold p-4 bg-red-50 rounded-lg"> ⚠️ {error} <button onClick={fetchWeather} className="block mt-2 text-sm text-red-700 underline mx-auto">Retry</button> </div> )}
{/* Success State */}
{!loading && !error && weather && (
<>
<h2 className="text-gray-500 font-semibold uppercase tracking-widest text-sm mb-6">New York, NY</h2>
<div className="text-7xl font-black text-slate-800 tracking-tighter mb-2">
{Math.round(weather.temperature)}°
</div>
<p className="text-xl text-slate-500 font-medium">
Wind: {weather.windspeed} km/h
</p>
<button
onClick={fetchWeather}
className="mt-8 bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-6 rounded-full transition w-full shadow-lg shadow-blue-500/30"
>
Refresh
</button>
</>
)}
</div>
</div>
);
}
``
11. Coding Challenges
Challenge 1: Modify the weather app to add a "City" text input. When the user types a city and hits enter, use dynamic URL parameters in the fetch request to fetch the weather for that specific city. *(You will need to find a suitable API endpoint that accepts city names).*
12. MCQs with Answers
Q1: What is the purpose of the .json() method when using the fetch API?
A) To send JSON data to the server.
B) To convert the raw HTTP Response body into a readable JavaScript Object.
C) To validate the data.
*Answer: B*
Q2: Why must the
fetch call in useEffect be wrapped in an async function?
A) Because useEffect itself cannot be defined as an async function directly.
B) For security reasons.
C) To make it run faster.
*Answer: A*
13. Interview Questions
-
Q: Explain the standard "three states" pattern for data fetching in React.
-
Q: How is Axios different from the native
fetch API?
14. FAQs
Do I always have to write fetch inside useEffect?
Not always. If you are submitting a form (POST request), the fetch happens inside the onSubmit handler, not inside useEffect. useEffect is specifically for loading data when a component appears or updates automatically.
15. Summary
Connecting to APIs breathes life into your applications. By combining useEffect for lifecycle management, fetch() or Axios for network requests, and useState` to manage Loading, Error, and Success states, you can build robust, data-driven frontends.