Fetching Data & APIs
Most React apps communicate with REST APIs. In this lesson we cover the full data-fetching lifecycle: loading states, error handling, caching, mutations, and optimistic UI updates.
1 Fetch with Loading & Error States
React — Complete Fetch Pattern
function PostList() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
fetch("https://jsonplaceholder.typicode.com/posts", {
signal: controller.signal
})
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then(data => { setPosts(data.slice(0, 10)); setLoading(false); })
.catch(err => {
if (err.name !== "AbortError") { setError(err.message); setLoading(false); }
});
return () => controller.abort(); // cancel on unmount
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{posts.map(post => (
<li key={post.id}><strong>{post.title}</strong></li>
))}
</ul>
);
}
2 POST / Mutations
React — POST Request
async function createPost(data) {
const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error("Failed to create post");
return res.json();
}
function NewPostForm() {
const [title, setTitle] = useState("");
const [saving, setSaving] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setSaving(true);
try {
const post = await createPost({ title, userId: 1 });
console.log("Created:", post);
} catch (err) {
console.error(err);
} finally {
setSaving(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input value={title} onChange={e => setTitle(e.target.value)} />
<button disabled={saving}>{saving ? "Saving..." : "Create Post"}</button>
</form>
);
}
3 Code Challenge
Challenge: Build a CRUD todo app using
https://jsonplaceholder.typicode.com/todos. Fetch 10 todos on mount, allow marking complete (PUT), and deleting (DELETE). Show loading spinners per operation.