Day 16 – Fetching Data in React (API Calls with fetch & axios)
5 mins read

Day 16 – Fetching Data in React (API Calls with fetch & axios)

Learn fetching data in React using fetch API and axios with async/await. Includes examples with loading and error states for beginners.

When building real-world apps, you rarely work with static data. Instead, your app will often need to fetch data from APIs — like fetching products from an e-commerce backend, posts from a blog API, or user info after login.

In React, data fetching is typically done using:

  • fetch API (built into browsers), or
  • axios (a popular HTTP library).

Both are often used together with the useEffect hook, because fetching is a side effect (it happens outside React’s rendering).

In this blog, we’ll cover:

  1. Basics of fetching with fetch.
  2. Fetching with axios.
  3. Using async/await for cleaner code.
  4. Handling loading and error states properly.
  5. Best practices.

Fetching Data with fetch API

The fetch API is built into modern browsers and allows you to make HTTP requests.

Example: Fetch Users

import React, { useEffect, useState } from "react";

function UsersList() {
  const [users, setUsers] = useState([]);   // stores fetched data
  const [loading, setLoading] = useState(true); // tracks loading state

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((res) => res.json()) // convert response to JSON
      .then((data) => {
        setUsers(data);    // store data in state
        setLoading(false); // stop loading
      })
      .catch(() => setLoading(false)); // handle network errors
  }, []);

  if (loading) return <p>Loading...</p>;

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          {user.name}{user.email}
        </li>
      ))}
    </ul>
  );
}

Explanation

  • useEffect ensures fetching happens after the component mounts (not on every render).
  • While waiting for the API, we display “Loading…”.
  • Once data arrives, we update state with setUsers(data) and render it.
  • The .catch() ensures our app doesn’t crash if the API fails.

Fetching Data with axios

While fetch works fine, many developers prefer axios because:

  • It automatically converts responses to JSON.
  • Has cleaner error handling.
  • Supports request cancellation, interceptors, etc.

Install axios

npm install axios

Example: Fetch Posts

import React, { useEffect, useState } from "react";
import axios from "axios";

function PostsList() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    axios
      .get("https://jsonplaceholder.typicode.com/posts")
      .then((res) => setPosts(res.data))
      .catch((err) => console.error("Error fetching posts:", err));
  }, []);

  return (
    <div>
      <h2>Posts</h2>
      <ul>
        {posts.slice(0, 5).map((post) => (
          <li key={post.id}>
            <b>{post.title}</b>
          </li>
        ))}
      </ul>
    </div>
  );
}

Explanation

  • axios.get(url) makes a GET request.
  • res.data contains the response (no need for .json()).
  • We only render the first 5 posts with .slice(0, 5) for brevity.

Using async/await for Cleaner Code

Instead of chaining .then(), we can use async/await for readability.

function Products() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchProducts = async () => {
      try {
        let res = await fetch("https://fakestoreapi.com/products");
        if (!res.ok) throw new Error("Failed to fetch");
        let data = await res.json();
        setProducts(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchProducts();
  }, []);

  if (loading) return <p>Loading products...</p>;
  if (error) return <p style={{ color: "red" }}>Error: {error}</p>;

  return (
    <ul>
      {products.map((p) => (
        <li key={p.id}>
          {p.title} – ${p.price}
        </li>
      ))}
    </ul>
  );
}

What’s Happening?

  • try { ... } catch { ... } finally { ... } ensures we handle success, errors, and cleanup.
  • If API fails, we display an error message instead of a blank screen.
  • This makes the app robust and user-friendly.

Best Practices for Fetching Data in React

  1. Always handle loading and error states. Never leave users guessing.
  2. Use useEffect properly with dependencies (avoid infinite loops).
  3. Use key when rendering lists (from API data).
  4. ✅ For complex apps, use React Query or SWR for advanced caching, retries, and background updates.
  5. Cleanup effects when fetching in components that may unmount.

Internal Links

External Links


Conclusion

Fetching data is one of the most essential skills in React. You can start with the fetch API, switch to axios for advanced needs, and always remember to handle loading and error states.

👉 Next Blog (Day 17): Async useEffect + Loading/Error States in React

Leave a Reply

Your email address will not be published. Required fields are marked *