Back
LearnReact — Build Modern Web AppsFetching data from an API

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

  1. Two states: users (the data, starts empty) and loading (starts true).
  2. useEffect(..., []) → runs once when the component appears, and calls fetch.
  3. When data arrives, setUsers(data) stores it and setLoading(false) hides the spinner.
  4. State changed → re-render. Now loading is false, so we map the 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 in useState, and render it with map. Handle loading and errors. This one pattern powers most real React apps.

Tip