How to Fetch API Data in React Using useEffect



This content originally appeared on DEV Community and was authored by Brian Cheruiyot

Fetching data from an API is a common task in React applications. The easiest way to handle this in functional components is by using the useEffect hook along with useState.

In this steps, we’ll learn how to:

  • Fetch API data in React
  • Show loading and error states
  • Render the data on the screen

Prerequisites

  • Basic knowledge of React and JavaScript
  • Node.js installed on your machine

1. Create a New React App

You can start with Create React App or any React boilerplate:

npx create-react-app fetch-demo
cd fetch-demo
npm start

2. Setup the Component

We’ll fetch data from the JSONPlaceholder API (a free test API).

Here’s the basic setup:

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

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

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((response) => response.json())
      .then((data) => setPosts(data));
  }, []);

  return (
    <div>
      <h1>Blog Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

What’s happening?

  • useState([]) → Stores the posts.

  • useEffect() → Runs after the component renders, fetching the data once.

  • fetch() → Gets the data and updates the state.

3. Add Loading and Error States

To make the UI better, let’s add loading and error handling:

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

function App() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((response) => {
        if (!response.ok) {
          throw new Error("Failed to fetch data");
        }
        return response.json();
      })
      .then((data) => setPosts(data))
      .catch((err) => setError(err.message))
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <div>
      <h1>Blog Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

Now your app:

  • Shows Loading… while data is fetched

  • Displays an error message if something goes wrong

You’ve successfully built a React component that fetches data from an API using useEffect and handles loading and error states. This pattern is essential for any real-world React application.


This content originally appeared on DEV Community and was authored by Brian Cheruiyot