What are common data fetching pitfalls in React?
The short answer
The most common pitfalls are: race conditions when the component re-renders during a fetch, missing cleanup that causes state updates on unmounted components, not handling loading and error states, waterfalls where requests run sequentially instead of in parallel, and not checking response.ok after a fetch call.
Pitfall 1: Race conditions
When a component re-fetches data (because a prop changes), the old request might finish after the new one:
1// Bug: if userId changes quickly, old response can overwrite new one2useEffect(() => {3 fetch(`/api/users/${userId}`)4 .then((r) => r.json())5 .then((data) => setUser(data));6}, [userId]);
If the user switches from ID 1 to ID 2, but the response for ID 1 arrives after ID 2, the component shows the wrong user.
Fix: Use AbortController to cancel the previous request:
1useEffect(() => {2 const controller = new AbortController();34 fetch(`/api/users/${userId}`, {5 signal: controller.signal,6 })7 .then((r) => r.json())8 .then((data) => setUser(data))9 .catch((err) => {10 if (err.name !== 'AbortError') setError(err.message);11 });1213 return () => controller.abort();14}, [userId]);
Pitfall 2: State updates after unmount
If a component unmounts while a fetch is in progress, the .then callback tries to set state on an unmounted component:
1// Warning: Can't perform a React state update on an unmounted component2useEffect(() => {3 fetch('/api/data')4 .then((r) => r.json())5 .then((data) => setData(data)); // component might be gone6}, []);
Fix: The same AbortController pattern cancels the request when the component unmounts.
Pitfall 3: Not checking response.ok
fetch does not reject on HTTP errors like 404 or 500. It only rejects on network failures:
1// Bug: 404 responses are treated as success2fetch('/api/users/999')3 .then((r) => r.json()) // tries to parse error page as JSON4 .then((data) => setUser(data));56// Fix: check response.ok7fetch('/api/users/999')8 .then((r) => {9 if (!r.ok) throw new Error(`HTTP ${r.status}`);10 return r.json();11 })12 .then((data) => setUser(data))13 .catch((err) => setError(err.message));
Pitfall 4: Request waterfalls
Fetching data sequentially when it could be done in parallel:
1// Slow — each request waits for the previous one2useEffect(() => {3 async function loadData() {4 const user = await fetch('/api/user').then((r) =>5 r.json()6 );7 const posts = await fetch('/api/posts').then((r) =>8 r.json()9 );10 const comments = await fetch('/api/comments').then(11 (r) => r.json()12 );13 setData({ user, posts, comments });14 }15 loadData();16}, []);1718// Fast — all requests run at the same time19useEffect(() => {20 async function loadData() {21 const [user, posts, comments] = await Promise.all([22 fetch('/api/user').then((r) => r.json()),23 fetch('/api/posts').then((r) => r.json()),24 fetch('/api/comments').then((r) => r.json()),25 ]);26 setData({ user, posts, comments });27 }28 loadData();29}, []);
Pitfall 5: No loading or error states
1// Bad — shows nothing while loading, crashes on error2function UserList() {3 const [users, setUsers] = useState([]);45 useEffect(() => {6 fetch('/api/users')7 .then((r) => r.json())8 .then(setUsers);9 }, []);1011 return (12 <ul>13 {users.map((u) => (14 <li key={u.id}>{u.name}</li>15 ))}16 </ul>17 );18}
The user sees an empty list while data loads, and if the request fails, the error is silently swallowed.
Common Pitfalls
The race condition pitfall is the most dangerous because it causes subtle bugs that are hard to reproduce. The component shows the wrong data intermittently, depending on network timing. Always use AbortController to cancel previous requests when the dependency changes, or use a library like React Query that handles this automatically.
Interview Tip
The race condition and response.ok pitfalls are the two that interviewers most want to hear about. Show you know how to fix race conditions with AbortController. Mentioning that fetch does not reject on HTTP errors surprises many interviewers — it is a well-known gotcha that many candidates miss.
Why interviewers ask this
Data fetching bugs are some of the most common bugs in React applications. Interviewers want to see if you are aware of these pitfalls and know how to avoid them. A candidate who mentions race conditions, AbortController, and response.ok shows they have dealt with real data fetching problems.