Skip to main content
React Introduction
CHAPTER 19 Beginner

Fetching Data from APIs

Updated: May 13, 2026
30 min read

# 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 native fetch() 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. 1. data: To hold the actual data once it arrives.
  1. 2. isLoading: A boolean to show a spinner while waiting for the network.
  1. 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 inside useEffect 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> ); }

123456789101112
## 5. Output Explanations
When the component mounts:
1. `isLoading` is `true`. The screen shows "Loading users...".
2. The `fetch` request goes out to the server. (Takes maybe 0.5 seconds).
3. The server responds. We convert the JSON and call `setUsers(data)`.
4. We call `setIsLoading(false)`.
5. The component re-renders. `isLoading` is false, so it skips the loading message and maps over the array, rendering the list of user names.

## 6. Using Axios (Alternative)
While `fetch()` is built into the browser, many companies prefer an external library called **Axios** because it automatically converts JSON and handles errors better.
*(Requires running `npm install axios`)*.

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); } };

123456789101112131415
## 7. Common Mistakes
- **Forgetting `.json()`:** `const response = await fetch(url); setData(response);`. This will fail. The `response` is an HTTP Response object, not the actual data. You must do `await response.json()`.
- **Not catching errors:** If you don't use a `try/catch` block and the server is down, your app will freeze indefinitely on the "Loading..." state.

## 8. Best Practices
- Always handle the loading state. Users hate clicking a button or opening a page and seeing absolutely nothing happen while the network request is pending.
- In enterprise applications, consider using data-fetching libraries like **React Query** or **SWR**. They handle caching, background updates, and error states automatically, saving hundreds of lines of boilerplate code.

## 9. Exercises
1. Find a free public API (like the Pokemon API or Rick and Morty API).
2. Create a component that fetches data from it and logs the JSON result to the console.

## 10. Mini Project: Weather App Integration
Let's build a functional widget that fetches and displays data from a mock weather API.

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&currentweather=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.

16. Next Chapter Recommendation

Passing state through multiple layers of components (prop drilling) can become very messy. How do we share data (like user authentication or UI themes) across the entire application globally? In Chapter 20: React Context API, we will solve this exact problem.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·