Tanstack Query v5 migration made easy – Key Aspects & Breaking Changes

Tanstack Query has become one of the most beloved tools of Web Developers for data fetching and state management in their applications. As of January 2024, it has just around 2.4 million weekly downloads and has become a first-choice option when it comes to asynchronously fetching, caching, and updating data which your UI relies on.  […]

by Atanas Ivanov

February 10, 2024

6 min read

tanstack query v5 migration

Tanstack Query has become one of the most beloved tools of Web Developers for data fetching and state management in their applications. As of January 2024, it has just around 2.4 million weekly downloads and has become a first-choice option when it comes to asynchronously fetching, caching, and updating data which your UI relies on. 

Since the official announcement of Tanstack Query v5, many developers, once upgrading to v5, are faced with a Tanstack Query v5 migration for their existing functionality, as the new version brought many of major changes. This can be a lot of work for mid to big enterprise web applications – the official Tanstack article is quite long, containing every change of the release itself, which can lead to passing over some modifications that can break your UI. 

This blog aims to give you the most commonly used functionalities that have breaking changes as well as some small changes but are quite often seen in a more structured way:

  • Major changes
  • New features
  • Minor changes.

As part of my work at a custom software development company, I had the chance to get familiar with the new version. Let me walk you through the most significant changes in Tanstack Query that you need going from v5 onward.

Migration Guide

First and foremost, don’t forget to run an npm install for the newest version (5.15.0 as of this writing) of Tanstack Query:

npm i @tanstack/react-query 

Also, from this version on there are new minimum versions of:

  • TypeScript – v4.7 and above
  • React – v18.0 and above

Major Changes

Support of a Single Signature 

Up until now, useQuery and its similar functions from TanStack had many overloads in Typescript. You could pass one or more parameters, which was hard to maintain type- and performance-wise since it required a runtime check. Therefore, from now on we have a single parameter – an object, containing the three “core” parameters as expected fields:

  • queryKey / mutationKey
  • queryFn / mutationFn
  • …options

This now is the standard for the whole API, not only query and mutation. Here are some examples (if some methods/hooks are missing they are analogical):

image 9 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

Hooks

image 10 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

queryClient methods

Removal of useQuery side effects 

      This is a huge change for the API itself – onError, onSuccess, and onSettled have been removed as callback fields of useQuery. Their benefit was also their biggest problem, leading to misconceptions – they triggered side effects. For example, you can show a “Toast” to the user if the query throws an error: 

image 3 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

This is very intuitive and that’s why developers love it. Without the callback, you have to write a useEffect hook to perform such a side effect:

unnamed 7 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

Many developers thought after having these callbacks, they wouldn’t have to write a single useEffect anymore, but unfortunately, that’s not the case. By using useEffect, the problem with this approach becomes a lot easier to see – if we call useServices two times in our app, we will get two error toasts! This is not so obvious with onError. 

For these types of scenarios, you can use the global callbacks on the queryCache – they will run only once for each query and cannot be overwritten which is exactly what we want!

image 6 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

Using callbacks for state syncing was not a good approach, as they potentially could be invoked multiple times, for example setting a state “on success”. Every time you do such a state update inside a callback, you make your app render more than necessary and the intermediate render cycle will contain false values.

There are the most common scenarios for the usage of the three callbacks, with  code snippets of the migration below: 

image 4 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

onSuccess migration

image 7 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

onError migration

Removal of isLoading in favor of isPending

The reasoning behind that is mainly the misleading name. Most people use isLoading to say to React “Show a loading spinner”. This was not always the case – for example, when data is pending, you wouldn’t necessarily show a loading spinner just because data is pending. And the previous isLoading was telling exactly that under the hood – “data is pending/hasn’t arrived yet”. That’s why it has been renamed to isPending

P.S. Now isLoading is the combination of the previous one and isFetching and it can be a perfect indicator of showing the loading spinner

New useSuspenseQuery

There is a new “suspense specific” hook – useSuspenseQuery. You no longer have to pass the suspense: true option on useQuery – that has been deprecated. The same applies to infinite queries as well. The benefit of these hooks is that data will never be potentially undefined on a type level.

image - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

cacheTime renaming to gcTime

This one is pretty straightforward – cache time got many developers confused as it can sound like “the amount of time data is cached for”, but that’s not correct. It only kicks in as soon as the query becomes unused. A more precise name is gcTime, where gc refers to “garbage collect”. The term is more technical but it is widely known among software engineers.

Filters removal for getQueryData and getQueryState

image 5 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

Replaced remove method with the removeQueries({ queryKey )} method

remove removal - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

keepPreviousData option removed in favor of placeholderData

keepPreviousData is now a function that can be imported from the library and be set as a value of the placeholderData option. This field accepts an identity function (a function that just returns its argument). Also, the boolean check for that has been renamed to isPlaceholderData

image 8 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

Infinite, infinite queries…

  • Required initialPageParam field – to remove the drawback of storing undefined in the query cache without a passed pageParam property in the callback, now you have to add it in each infinite query call
  • Manual mode for infinite queries has been removed – in previous versions, pageParams returned from getNextPageParam or getPreviousPageParam were modifiable directly – this did not at all with refetches and wasn’t so commonly used. Therefore this option has been removed and getNextPageParam field is required for infinite queries.
initial page param inf - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

New Features

Tanstack Query v5 doesn’t just come with migrating/refactoring existing functionality or achieving the same result differently. There are some new features as well.

  • Optimistic updates got simpler – you can now easily perform optimistic updates by leveraging the returned variables from the useMutation hook
optimistic update - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes
  • Limited, Infinite Queries with maxPages option – removed refetchPage in favor of maxPages 

Refetching all pages might lead to inconsistent UI – for that, we have a new maxPages option that limits the number of pages to store in the query and to refetch

  • Infinite Queries can prefetch multiple pages – infinite queries can be prefetched like regular queries
  • New combine option for useQueries – if you want to combine data or any other query information from the results in a single value; note that all other properties of query results will be lost
image 2 - Tanstack Query v5 migration made easy - Key Aspects & Breaking Changes

Minor Changes

Here are some minor changes that are less commonly used. I decided to write them down here as the ones above are more breaking and major – these you will not see that often:

  • Window focus refetching no longer listens to the focus event. This fixes a lot of issues related to unexpected/unnecessary query refetches.
  • Removed custom context prop in favor of custom queryClient instance – context is a react-only feature. We can achieve the same encapsulation by passing a customer queryClient directly as the second argument of the useQuery hook.
  • Fields and methods on classes have always been private but in TypeScript – now TanStack Query uses ECMAScript’s private class features which makes these fields truly (JS) inaccessible.
  • TypeScript: Error is now the default type for errors instead of unknown – if you want to throw something in your query function that is not an Error you need to set the generic yourself
  • useErrorBoundary renaming – the option has now been renamed to throwOnError as it more accurately reflects its functionality and to avoid confusion with the function prefix “use” for hooks

Conclusion

There are a lot of new patterns that have to be adopted in each up-to-date project and every developer uses TanStack Query in v5. The API is going in a better direction with these updates and most of them are upgrades to the library. If you want to see the official migration guide and see every change, you can check it out here.

I hope this article gave you a better understanding of what is major/minor and more commonly seen in different web applications using TanStack Query and can serve you as a guide for a lighter, easier-to-follow migration to the newest version. 

Categories

Middle Software Engineer at Dreamix