logo
Technology

How we supercharged our Auction flows with TanStack query

Bharat Gupta
Jun 6, 2025
3 minutes

Efficient state management is crucial when building a React Native app. Managing auctions, documentation, and other operations required careful handling of server and UI state. Initially, we relied entirely on Redux, but as the flow grew, challenges started piling up.

That’s when we brought in TanStack Query for optimizations. Let’s explore the problems we faced and how TanStack Query helped us overcome them.

The Problems

  1. Slow Navigation:
  2. We fetched all the required data upfront and stored it in Redux. This blocked navigation until all data was loaded, causing noticeable delays on slower networks.
  3. Boilerplate Overload:
  4. Managing loading, error, and refetching required extensive boilerplate code with actions, reducers, and dispatch logic.
  5. Caching Challenges:
  6. Storing long-term cache for static content (e.g. CMS data) alongside dynamic data refresh for user actions was cumbersome with Redux.

The Solution: Why TanStack Query

We introduced TanStack Query, which allowed us to offload server state (data coming from the backend) management from Redux while maintaining UI state (e.g., when increasing/decreasing price or state of the auction) in Redux. This hybrid approach reduced complexity and significantly improved performance. Here’s what we did:

1. Leveraging Query Keys for Modular State Management

To make query management easier, we structured all query keys with a common prefix (auction). This allowed us to manage all queries related to auctions as a group efficiently.

useQuery({
 queryKey: ['auction', 'details', id],
 queryFn: () => getAuctionDetails(id),
 staleTime: Infinity, 
 gcTime: 5 * 60 * 1000, 
});

2. No boilerplate code required

We no longer needed Redux boilerplate for managing loading and error states. The library’s built-in variables handled it gracefully:isLoading ,isError ,refetch

const AuctionDetailsScreen = ({ id }) => {
 const { data, isLoading, isError, refetch } = useQuery({
 queryKey: ['auction', 'details', id],
 queryFn: () => getAuctionDetails(id),
 staleTime: Infinity
 });

 if (isLoading) return <LoadingSpinner />;
 if (isError) return <ErrorScreen onRetry={refetch} />;

 return <AuctionDetails data={data} />;
};

3. Avoiding Prop Drilling

TanStack Query allowed us to reuse the same query hook in child components without needing to prop drill data from parent components. If the staleTime is long enough, the data is fetched from the cache instead of making another API call.

import { useQuery } from '@tanstack/react-query';

const useAuctionDetails = (id) => {
return useQuery({
queryKey: ['auction', 'details', id],
queryFn: () => fetchAuctionDetails(id),
staleTime: 60 * 60 * 1000,
});
};

const ParentComponent = ({ id }) => {
const { data, isLoading } = useAuctionDetails(id);
if (isLoading) return <LoadingSpinner />;
return (
<div>
<h1>{data.title}</h1>
<ChildComponent id={id} />
</div>
);
};

const ChildComponent = memo(({ id }) => {
const { data } = useAuctionDetails(id); // Reuses the same cached data
return <p>{data.description}</p>;
});

4. Efficient Cache Management with staleTime and gcTime

TanStack Query allowed us to control data freshness and memory usage effectively:

  • Static Content (e.g., CMS Data):
useQuery({
 queryKey: ['auction', 'cms-data'],
 queryFn: fetchCMSData,
 staleTime: Infinity, 
 gcTime: 24 * 60 * 60 * 1000, // Cache for 24 hours
});
  • Dynamic Content (e.g., Auction Details):
useQuery({
  queryKey: ['auction', 'details', id],
  queryFn: () => getAuctionDetails(id),
  staleTime: Infinity
  gcTime: 5 * 60 * 1000, // Cache for 5 minutes
});

5. Advanced Query Functions

TanStack Query provides powerful utility functions to manage query state. Here’s how we used them:

Prefetch Queries

To preload data before the user navigates to a screen:

queryClient.prefetchQuery({
queryKey: ['auction', 'details', id],
queryFn: () => getAuctionDetails(id),
});

Get Query Data

Retrieve the cached state of a query:

const data = queryClient.getQueryData(['auction', 'details', id]);
console.log('Cached data:', data);

Fetch Fresh Data

Forcing a fresh fetch requires a combination of invalidateQueries and getQueryData:

await queryClient.invalidateQueries({ queryKey: ['auction', 'details', id] });
const freshData = queryClient.getQueryData(['auction', 'details', id])?.data;

Clearing cache after flow completion

To refresh all queries that start with auction:

queryClient.resetQueries({
queryKey: ['auction'],
exact: false, // Clear all queries starting with 'auction'
});

If exact is false , all queries starting with auction are reset.

6. Debugging with React Query DevTools

The react-native-react-query-devtools plugin made it easy to debug queries by visualizing their state, cache, and fetch cycles.

Conclusion

Switching to TanStack Query transformed how we handle server state, making our app faster and easier to maintain. Thanks for your time.

Loved this article?

Hit the like button

Share this article

Spread the knowledge