A few weeks ago, the React community was buzzing after the useEffect debacle at Cloudflare.
If you’re not aware of what happened, don’t worry — I’l...
For further actions, you may consider blocking this person and/or reporting abuse
Nice article. I liked it.
However, I have one big question, is it possible to combine redux with its asynchronous thunks (or another tool for centralization the data) and TanStack Query. And if possible, what is the best and elegant way?
Thanks! Glad you liked it 😊
Yes, you can use Redux and TanStack Query together since they serve different purposes.
Redux (or thunks) works best for client state such as UI elements, filters, and toggles.
TanStack Query is ideal for server state which comes from APIs and can change outside your app.
You can sync them by dispatching inside onSuccess, but it’s usually cleaner to let TanStack Query manage server data and keep Redux for UI logic.
Fine! Thank you for explanation, it's very clear and i appreciate it. Waiting for your new articles ☺️.
onSuccess callback has been removed since doing exactly this was considered an anti-pattern. tkdodo.eu/blog/breaking-react-quer...
Stating that redux is for client state and TanStack Query is also clumsy. Not redux neither TanStack Query states that. Also TanStack Query is not only for syncing server data. It's a state management library that's convenient for any asynchronous data and actually making reactive state from them. Instead of fetch, it could be anything async. E.g. MediaDevices.getUserMedia which returns Promise.
You’re right that onSuccess, onError, and onSettled were removed from useQuery in v5 to discourage side effects during render. But are still available and recommended for useMutation, since mutations represent explicit user actions.
(Docs: tanstack.com/query/latest/docs/fra...)
I agree that TanStack Query can handle any async data, not just HTTP calls. But its core design and documentation describe it as an async state library optimized for server state, meaning data that can become stale, needs caching, or background refetching.
Redux or Zustand works better for client or UI state, such as filters, toggles, or input. TanStack Query is not intended to replace that kind of local state management.
So while it can be used for any promise-based data, the practical distinction still makes sense:
TanStack Query - Server or async state
Redux - Client or UI state
That’s also the pattern most teams follow.
useMutation is totally different story, the article isn't about it at all, it does not serve as wrapper around data synced into the client app. It rather helps monitor event based async requests.
The thing is that redux/zustand/... could also serve as storage for the promise based data however as lower level storage. TanStack Query brings another tools like caching or state tracking (isSuccess/isLoading/...) but with a tradeoff. There are use cases where TanStack Query does not fit and these situations need to be solved ad hoc however e.g. redux still can help holding the data.
Great article, switching to TankStack Query, thanks!
Thanks! Glad you found it helpful.
Tanstack query uses useEffect internally though...
True, it uses useEffect internally, but that’s the point.
It abstracts all the tricky parts like caching, retries, and race conditions so you don’t have to deal with them in every component.
The goal isn’t to avoid useEffect, but to use it in a safer, consistent way.
That's a big assumption that tanstack query uses useEffect in a safe way 😛