Fetching data from an API
2 min read
The most common real-world task
Almost every real app loads data from a server when it opens — a feed, a product list, a profile. In React, you combine three things you already know: useState (to store data), useEffect (to fetch when the page opens), and fetch (to call the API).
The standard data-fetching pattern
import { useState, useEffect } from "react";
function Users() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((data) => {
setUsers(data);
setLoading(false);
});
}, []);
if (loading) return <p>Loading...</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Let me walk through it — this pattern is everywhere
- Two states:
users(the data, starts empty) andloading(startstrue). useEffect(..., [])→ runs once when the component appears, and callsfetch.- When data arrives,
setUsers(data)stores it andsetLoading(false)hides the spinner. - State changed → re-render. Now
loadingis false, so wemapthe users into a list.
Always handle loading and errors
A good data UI handles three states: loading, success, and error. Add a .catch for failures:
.catch((err) => {
setError("Could not load users");
setLoading(false);
});
Show a spinner while loading, the data on success, and a friendly message on error. Real apps always do this.
Fetch with
useEffect(..., [])+fetch, store the result inuseState, and render it withmap. Handle loading and errors. This one pattern powers most real React apps.