There have been endless discussions about state management in React. React Query solved the most common and most annoying part of state management for me, which was everything that you fetched via the network. The part that remains is straightforward enough with the built-in useState/useReducer.
It does take a moment to learn React Query. You should make sure everyone understands how query keys work and uses them correctly. I saw some confusion there when we started using it, and one developer trying to work around stuff manually that React Query does automatically if you properly set up your query keys and invalidate them.
It was more of a general misunderstanding on how React Query is supposed to work, partially triggered by some mistakes in defining the query keys that meant that React Query didn't work as intended.
I'd recommend this blog post (or actually all blog posts on React query on that site):
What I observed was that the query keys were not consistently defined, which broke automatic refetching when the data was modified and invalidated. So the developer added some manual refetches because they thought React Query couldn't handle that automatically.
You need a consistent structure for your query keys and use that everywhere. Then you only need to make sure to invalidate the correct part of the query key hierarchy and the rest works automatically.
First: Realize that React Query isn't a library for fetching data, but a library for caching the fetched data. So think about how you will be invalidating that cache. For us, the rule of thumb was that each fetch to the API should have it's own cache key in React Query.
Second: The data in cached in React Query is effectively globally available, so it comes with all the benefits and pitfalls that globals have. We use Storybook and do not use React Query in the components that have stories, so React Query is only used in the root components of the app.
ReactQuery state is not global. It's set in a context, and it takes two lines to write a Storybook decorator that ensures a unique cache for each story.
It may still make sense to keep react-query out of your storybooks though.
I would almost consider this a default package to use in a react application for server-side state. Any mildly complex UI will almost immediately need init/loading/error/data states, and you begin to write a wrapper that trends towards what react-query gives you. It makes it a lot easier to by default, write code that provides much better UX. The improvement there far outweighs the small amount of time it takes to learn the library and overhead it introduces.
I've been using React-query on several projects including the v5 on a recent one.
On a new project I decided to give a try to RTK (Redux ToolKit), I must say there's not much reason to not use RTK over a lib like react-query. You basically have the same and more, and all the advantages of using react-redux.
It felt backward at first to come back to Redux after all this time, but I'm glad I did, and can't recommend it enough. (and the project is still active)
Hi, I'm a Redux maintainer. Yeah, Redux Toolkit includes our RTK Query data fetching and caching layer [0] [1], which is roughly equivalent in features and use case to React Query.
In fact, the React Query and Redux maintainers cross-recommend each other's libraries. If you're _not_ using Redux in an app, use React Query for your data fetching. If you _are_ using Redux in an app, use RTK Query for your data fetching.
(There are some differences in features and API design that might be a reason to use RTK Query even if you're not using Redux for client-side state management, such as the OpenAPI/GraphQL codegens, auto-generated React hooks, etc [1] )
In one of my recent projects I've used rtk in combination with their openApi generator and that was one of the fastest developed apps I've made. Having all hooks ready from a single command is just great.
Redux is great, sure. But it's not a great fit for all applications, or maybe even most.
The largest need for state management in most react applications is for so-called "server state", which is really just data from your backend. RQ lets you deal with that elegantly without buying into any other major state management solution like redux.
If you are already using redux for other reasons, RTK Query is a no-brainer. But if you aren't, something like RQ is probably a better choice.
React-query does have a state management, like redux. You can use RTK "the same way" than react-query, and it comes with more if needed, that's why I don't see real reason to prefer RQ over it
Edit: Also, IMO RTK enforce cleaner code/structure than RQ
Never used RTK, just plain redux. But for me it was always unnecessary ceremony. Most application state is rather simple, once you properly organize it into "real" state and computed values.
I think it vastly depends what you use redux for. If you have very complex local state, that is not always in sync with the server, than it may be the right thing to do. For example something like draw.io.
But just for fetching/mutating server data more or less synchronously (view, edit, save) it feels very unnecessary.
that's always the same critic people (including me) have, but RTK moslty solve that
> But just for fetching/mutating server data more or less synchronously
With RTK you can basically have the same simple usage (with better structure IMO), and if needed you have all the power of redux, side-effect, ready to use
Our team is currently debating whether we should adopt react-query or stick with plain old hand-written code around `fetch`. The team used Apollo in another project, so we are quite familiar with a "heavy handed wrapper" around backend requests. But I'm not sure the added complexity of react-query is "worth it".
Anyone have experiences to share, either using react-query, a different library or particularly painful memories _not_ using a comparable library?
Had a good experience with RTK Query, lives under redux toolkit but does much more than just reducing the boilerplate for redux which I don't think many people have noticed
I migrated a project to it from react query last year as we liked the react query style hooks and some of its behaviour, but found our usage of react query was getting a bit messy when we started adding dozens and dozens of more endpoints in a large app. Lots of things felt spread out and duplicated, we wanted to centralise things a bit (and simplify the typing) without adding a ton of custom hooks or abstractions
With RTK Query we got to move all the endpoint definitions, cache invalidation behaviour (we had many endpoints that used parameters from many other endpoint responses) and TS definitions to a single place. Also it uses redux underneath so we got the redux tools as well
I'd still use either projects again in the future, just depends on the project
RTK Query felt really good when dealing with a ton of microservices, but maybe overkill if you don't have a ton of endpoints where responses feed into other request parameters
Saw a team trip all over themselves trying to implement the pagination and also introduced a bunch of caching bugs(predictable any time caching is introduced).
It's cool that it's ALSO a general pattern for any async call, but it's really heavy for just that if you don't want the caching and stuff.
Personally I'm just sticking with MobX and more straightforward fetching mechanics.
Best thing you could do, spend some time learning how it works properly (query keys, invalidations... ) and how you'd set up things like pagination.
If at any point anyone goes like "oh it doesn't seem to support this, we'll have to write some wrappers/custom stuff", take a step back and read the docs again or ask around - the library in general takes care of everything it should and gets out of the way really well otherwise.
In my opinion react query doesn't really add complexity if you just use to "await" your fetches. It even comes with the nice added functionality to refetch everything when refocusing the browser. And some automatic error handling.
Once you need query invalidation it gets really useful.
But it also depends how you use fetch right now. If you do it on per-route basis, than react query might not bring a lot of benefits.
Mix of both. Some data needs to be ready on page load, but we also have quite a number of interactive use cases (e.g., form validation with a backend query).
I spent a couple of years on a project that used React Query with Axios. The massive advantage over plain fetch was the middleware API. If you want to do things like injecting an auth header or clientside token refresh it's really useful. That was more Axios than React Query though.
I've tried plain fetch + useEffect + useState. It's very easy to mess up the implementation. For example you have to think about what happens if the useEffect triggers again while it is already fetching. For reasons like that, react-query is totally worth it to me.
Looks interesting. Thanks! Not sure how I feel about the key being handed to the fetcher (might be great, might be annoyingly verbose). Will have to see what it looks like in practice. (We are going to use feTS [0] or openapi-fetch [1], which are very particular about how the path is assembled)
Writing your own backend for GraphQL doesn't scale. You should stick to no-code solutions that can auto generate graphQL on top of existing APIs. Checkout https://tailcall.run
I currently use SWR. Is there a reason to choose tanstack query over SWR? A cursory look shows them to be near identical in scope, but tanstack is ~3x the bundled size. AFAICS there isnt anything that SWR doesnt support either OOTB or via minor modification to the fetcher (e.g. cancellable requests).
There are some nice to have features in React Query off of the shelf, but nothing I’m aware of that can’t be accomplished with SWR if needed. There’s scroll restoration and offline mutations primarily. I’ve never actually needed either of those, and I personally prefer SWR because it’s so lightweight, out of the way, and portable. One thing RQ definitely has over SWR is better dev tools, but I’ve never actually needed or wanted them for either library.
People do seem to prefer RQ generally, maybe because it’s a bit more intuitive and better documented. It might be a better choice for more complex caching and mutating needs. SWR is still so easy and intuitive as it is, so I haven’t seen a reason to prefer RQ by default.
OOTB offline-first sounds handy. With SWR I had to modify the fetcher to query and store in indexedDB and then later replay to remote, which while not exactly difficult did require some effort.
I guess its worth giving it a spin and see for myself :)
Thats a good point. I checked using the "better" tool (pkg-size.dev) they show on your link and it seems they are actually comparable for the "default" export (but im not sure what that gives me with tanstack query - its effectively everything with SWR).
The dev tools of react query did it for me. Much easier to see what's going on. Especially if you are not completely familiar with all the concepts yet.
Also I think react query has more options (you may or may not find useful).
I've been using v5 in production since beta 20, and it has been working very reliable for us since then. The documentation for how to upgrade has been a great resource, and a great example of how to do breaking changes in a library as large as this one.
I've seen multiple projects, in which people try to save results of requests into global state using Redux (not rtk), Zustand etc. and I have never seen it done well. React Query and Redux toolkit really should be the default options for request state management.
> Apart from that, we've renamed cacheTime to gcTime to better reflect what it is doing
Does it though? Maybe it's super obvious to more experienced users, but now I need to read the docs to find out what "gc" stands for. Not a big deal, just seems like an unnecessary abbreviation, so I'm curious as to what the reasoning is.
which is likely much better than making the wrong assumption because you know what "cache" means. Check the docs, cacheTime is very likely not doing what you expected.
A typical expectation would be that "cacheTime" controls how long react query uses the cached value before it tries to fetch that data again from the server. That part is actually controlled by "staleTime".
so cacheTime was really confusing because it seemed like "this is the amount time we cache data for", but that's not what it is. So a rename had to happen. We had some discussion on the public roadmap (https://github.com/TanStack/query/discussions/4252) about what it's gonna be. I'm usually against abbreviations, simply because there's always someone who doesn't understand what it means. But all other suggestions like inactiveCacheTime also had room for interpretation. gc is an abbreviation that is known well enough (think git gc), and it's also not an option that you will customize on a daily basis (usually once, globally).
Not gonna lie: that sounds absolutely awful, and I can't imagine this works at any real scale. It will also have poor UX, because your users will be waiting for data which you already fetched and should just have cached.
There are also plenty of applications where what you are describing is arguably just not feasible at all, like heavier applications that due to their nature just need a lot of client-side state.
If you have a fast API it's very feasible. I'll take slighly reduced UX due to slower page load times any day over unpredictable completely broken UX introduced by bad state management (common with e.g. Redux non-RTK in the hands of inexperienced frontend devs).
I'd personally still favor Next.js + TanStack Query if given the choice.
I send it in a custom event to the part of the system that needs it.
Or I ask multiple times.
Asking multiple times is a tradeoff - if you are really needing to economise on back end server load then maybe front end caching matters more. But if your back end isn't going to mind, then ask again.
It does take a moment to learn React Query. You should make sure everyone understands how query keys work and uses them correctly. I saw some confusion there when we started using it, and one developer trying to work around stuff manually that React Query does automatically if you properly set up your query keys and invalidate them.