Fetching data from an API and showing it in the UI is a core part of most React apps. You run the fetch inside `useEffect` when the component mounts, and manage the loading/data/error state with `useState`.
jsx
import { useEffect, useState } from 'react';
function Post() {
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
useEffect(() => {
async function loadPost() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
if (!response.ok) throw new Error('Failed to load post');
const data = await response.json();
setPost(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
loadPost();
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>{error}</p>;
return <h1>{post.title}</h1>;
}The API call happens right after the component's first render. On success, the data goes into the `post` state; on failure, the error goes into `error`; either way, loading gets set to false at the end.
You should see
Loading shows first, and once the data arrives, the post title appears. If the API has an issue, an error message shows instead.Info
Real projects add things like API URLs, auth tokens, pagination, retries, and caching — but the basic pattern is still just cleanly managing loading/data/error.