SyntaxStudy
Sign Up
React Data Fetching with useEffect and fetch
React Beginner 1 min read

Data Fetching with useEffect and fetch

The most basic approach to API calls in React is using the native fetch API inside a useEffect hook. You initiate the fetch inside the effect body, parse the JSON response, and store the result in state. Adding a cleanup flag or an AbortController prevents state updates on unmounted components, which would otherwise produce a React warning. Handling loading and error states explicitly — rather than relying on the data being null — produces a better user experience and avoids rendering components with undefined values. The three-state model (loading, error, success) maps cleanly to conditional rendering in JSX. This bare-bones approach is suitable for small applications or for fetching data that is needed only once. When you need caching, background updates, pagination, or retry logic, a dedicated data-fetching library provides all of that with much less code.
Example
import { useState, useEffect } from 'react';

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

    useEffect(() => {
        const controller = new AbortController();

        async function load() {
            try {
                const res = await fetch('https://jsonplaceholder.typicode.com/posts', {
                    signal: controller.signal,
                });
                if (!res.ok) throw new Error(`HTTP error ${res.status}`);
                const data = await res.json();
                setPosts(data.slice(0, 10));
            } catch (err) {
                if (err.name !== 'AbortError') setError(err.message);
            } finally {
                setLoading(false);
            }
        }

        load();
        return () => controller.abort();
    }, []);

    return { posts, loading, error };
}

function PostList() {
    const { posts, loading, error } = usePosts();

    if (loading) return <p>Loading posts…</p>;
    if (error)   return <p style={{ color: 'red' }}>Error: {error}</p>;

    return (
        <ul>
            {posts.map(post => (
                <li key={post.id}>
                    <strong>{post.title}</strong>
                    <p>{post.body}</p>
                </li>
            ))}
        </ul>
    );
}