How to Fetch Data With useEffect in React the Right Way
Fetching data with useEffect is a core React skill. Here is the correct pattern, including dependencies, cleanup, and race conditions.
How to Fetch Data With useEffect in React the Right Way
Fetching data with useEffect is one of the first things you learn, and one of the easiest to get wrong. Here is the correct pattern.
The Basic Pattern
Declare state for data, loading, and error. Inside useEffect with an empty dependency array, call the API, store the result, and handle errors.
Use a Cleanup Flag
Declare a flag that tracks whether the component is still mounted. In the cleanup function, set it to false. Only update state if the flag is still true, so you avoid updating state after unmount.
Or Use an Abort Signal
For fetch, use an AbortController. Pass its signal to the fetch call, and abort it in the cleanup. This actually cancels the network request, which is cleaner than a flag.
Handle the Response Shape
Read the actual response. The data is often nested inside an object, so extract the array you need before mapping over it.
Handle All Three States
Show a spinner while loading, an error with a retry on failure, and the data on success. Never leave the user with a blank screen.
Avoid Infinite Loops
If you set state inside the effect and include that state in the dependency array, you create an infinite loop. Use an empty array for one-time fetches, or include only the values the fetch depends on, like an id.
The Takeaway
Fetch in useEffect with the right dependency array, handle loading and error, guard against unmount with a cleanup flag or abort signal, and read the response shape correctly. That is the right way.
Declare state for data, loading, and error. Fetch inside useEffect with an empty dependency array, handle the response shape, and guard against unmount with a cleanup flag or abort signal. Handle all three states: loading, error, and success.
Use a cleanup flag that tracks whether the component is still mounted, or use an AbortController to actually cancel the request. Only update state if the component is still mounted, so you avoid the warning about updating state on an unmounted component.
Because you included a state variable in the dependency array that you update inside the effect. Each update triggers another fetch. Use an empty array for one-time fetches, or include only values the fetch actually depends on, like an id.
Yes, it is cleaner than a flag. Pass the controller's signal to fetch, and abort it in the cleanup function. This actually cancels the network request instead of just ignoring the result, which is better for performance and correctness.
Because you assumed the data is an array when it is nested inside an object. Read the actual response shape, extract the array from the correct field, and only then call map on it.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

