Skip to content
The App Code
How-to

Fetch Data in React with useEffect

Load data on mount inside useEffect, storing the result in state and cleaning up to avoid setting state after unmount.

Also known as: React data fetching, useEffect fetch

intermediate

Run the request in useEffect with a dependency array, save the result with useState, and use an ignore flag in cleanup so a late response can't update an unmounted component.

What it is

In React you fetch data as a side effect: put the call in useEffect and store the outcome in useState. The dependency array controls when it re-runs — [] means once after mount, [id] re-runs when id changes.

Because a component can unmount (or the input can change) before the request finishes, use a local ignore flag set in the effect's cleanup function. If the effect re-runs or the component unmounts, ignore becomes true and the stale response is discarded, preventing a race condition and the classic warning about updating state on an unmounted component.

Worked example

import { useEffect, useState } from "react";

function Post({ id }) {
  const [post, setPost] = useState(null);

  useEffect(() => {
    let ignore = false;
    fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
      .then((res) => res.json())
      .then((data) => {
        if (!ignore) setPost(data);
      });
    return () => {
      ignore = true;
    };
  }, [id]);

  if (!post) return <p>Loading…</p>;
  return <h1>{post.title}</h1>;
}

Failure mode — when it misleads

Forgetting the ignore cleanup causes race conditions when id changes quickly: an earlier, slower response can overwrite a newer one. Omitting a value used inside the effect from the dependency array leads to stale data. For anything beyond trivial cases, a library like React Query or SWR handles caching, dedup and cancellation for you.

Sources & further reading