Every React dev has written this at least once.
useEffect(() => {
fetchData();
}, []);
It works sure. But once your app gets a bit bigger this pattern starts causing problems, specially performance and backend load.
I'm a Mern stack developer and for a long time i just used useEffect for every single api call in my apps, until i actually tried Tanstack React Query properly. Now i barely write a raw useEffect for fetching data anymore.
Here is why i made the switch.
Your API Gets Called Twice (and its not a bug)
If you're using React 18 with StrictMode, you probably noticed your effects run twice in development. This is intentional, React does this to help catch side effect bugs. But it also means your api is getting hit 2 times on mount which confuses a lot of devs, and even in production if a component remounts often, useEffect fires again and again without any smart caching.
That means more load on your backend for no real reason.
React query fixes this because it caches by query key. If the data is already there and still "fresh" it wont refetch, it just returns the cached data instantly.
Boilerplate for Loading and Error States
With plain useEffect you end up writing this same block over and over.
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
Do this for every single fetch in a medium size app and you got a lot of repeated code, plus more chances of bugs, like forgetting to reset loading in the catch block or not handling cleanup on unmount.
React Query gives you all this for free from the hook itself, isLoading, isError, data, error, done.
No More Dependency Array Guessing
Dependency arrays are one of the most confusing part of hooks for beginners and even experienced devs mess it up sometime. Missing a dependency causes stale data bugs. Adding too many causes unnecessary re renders and re fetching.
React Query removes this whole problem. You give it a query key and a fetch function, that's it. It manages refetching based on mount, focus, or your staleTime settings, not a manually managed array.
The Real Power: Cache, StaleTime and Invalidation
These are the 3 features that actually changed how i build react apps.
Cache: data fetched once is stored under its key, come back to same page and you instantly see data while it refreshes quietly in background if its stale.
staleTime: tells react query how long the data stays "fresh". Fresh data means no unnecessary refetch, which directly reduces backend calls.
invalidateQueries: after a mutation like updating or deleting something, you just invalidate the related query key and react query refetches it automatically. No manual syncing of state after mutations.
Once you use these together, most of the manual data fetching logic you used to write with useEffect just disappears.
A Project Where This Actually Mattered
I worked on a Next js SaaS platform recently where the dashboard was firing multiple api calls on every tab switch, all because of useEffect running on every mount. The backend was getting hammered with repeated requests and users noticed the slow loading.
After replacing useEffect with react query, adding staleTime, and using invalidateQueries for mutations, the whole dashboard felt way faster and the backend load dropped a lot. That project is live here if you want to see it, it was a Next.js SaaS Platform built for managing mineral owner contact data.
Is useEffect Useless Now
No, not at all. useEffect still has its place for things like subscriptions, event listeners, timers, syncing with non react code etc. Its just not the right tool for data fetching anymore, specially when a purpose built library like react query exists and handles it so much better.
Wrapping Up
As a Mern stack developer i learned this the hard way, after debugging way too many "why is my api getting called 3 times" issues that all came back to useEffect misuse. Switching to react query fixed most of it instantly, and gave me caching and invalidation on top, basically for free.
If you're building serious apps and want to reduce backend load while writing cleaner code, i'd say give react query a shot on your next project. As someone who works as a Full stack Mern & Next.js developer, this is one of those changes i recommend to almost every team i work with now.
I have covered some common issues with Tanstack here, Common React Query Issues, Query Key and Invalidate Queries Problems Explained, where i explained why invalidate queries sometime dont work and how to fix pagination, update and delete cases properly.
Let me know if you already use react query or still on useEffect, curious to hear what others think.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.