Effects and Data Fetching
💻 ReactLoad data with useEffect, handle loading and avoid race conditions.
An effect runs after render. It is the right place for fetching data, setting up subscriptions and syncing with something outside React.
- Fetch data in useEffect.
- Handle loading and errors.
- Clean up an effect.
Fetch on Mount
An effect with an empty dependency array runs once after the first render.
import { useEffect, useState } from "react";
function Students() {
const [students, setStudents] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function load() {
try {
const response = await fetch("/api/students");
setStudents(await response.json());
} finally {
setLoading(false);
}
}
load();
}, []);
if (loading) return <p>Loading…</p>;
return <ul>{students.map(s => <li key={s.id}>{s.name}</li>)}</ul>;
}Avoid Race Conditions
If the component unmounts before the request finishes, state updates are wasted. Use an abort controller to cancel the request and ignore late results.
useEffect(() => {
const controller = new AbortController();
fetch("/api/students", { signal: controller.signal })
.then(response => response.json())
.then(setStudents)
.catch(error => {
if (error.name !== "AbortError") setError(error.message);
});
return () => controller.abort();
}, []);Dependencies
List every value the effect reads. An empty array means run once; omitting the array means run after every render, which is rarely what you want.
Practice
- Fetch a list of posts and render the titles.
- Show an error message when the request fails.
- Add a refresh button that re-runs the fetch.
Hands-on exercise
Build a Posts component that:
1. Fetches /api/posts on mount.
2. Shows Loading while waiting.
3. Shows an error message on failure.
4. Renders each post title with its id as the key.
Recap
Effects run after render and are the right place for data loading. Clean up requests and list dependencies honestly.
Example
import { useEffect, useState } from "react";
function Students() {
const [students, setStudents] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function load() {
try {
const response = await fetch("/api/students");
setStudents(await response.json());
} finally {
setLoading(false);
}
}
load();
}, []);
if (loading) return <p>Loading…</p>;
return <ul>{students.map(s => <li key={s.id}>{s.name}</li>)}</ul>;
}
Exercises
1. Fetches /api/posts on mount.
2. Shows Loading while waiting.
3. Shows an error message on failure.
4. Renders each post title with its id as the key.
Expected Output
Loading, error and success states all handled.
Lesson Nav
React Course
0/9 lessons completed
- 1 Thinking in Components Tutorial
- 2 Props and Composition Tutorial
- 3 State and Events Tutorial
- 4 Lists, Keys and Conditional Rendering Tutorial
- 5 Forms in React Tutorial
- 6 Effects and Data Fetching Tutorial
- 7 Routing and Layouts Tutorial
- 8 Context and Shared State Tutorial
- 9 Project: A Student Dashboard Project