Controlling Refetching in RTK Query (The Human Way)

Prashant Adhikari
Dec 19, 20253 min read
If you’ve ever used RTK Query and wondered:
“Why did this fetch again?”
“How do I refresh data only when I want?”
“How do I stop unnecessary network calls?”
You’re not alone.
RTK Query is powerful, but refetching behavior can feel confusing at first. This post breaks it down in a simple, human way, so you always know when data fetches again — and why.
The Default Behavior (Good News First)
By default, RTK Query is smart.
It caches data
It reuses cached data
It avoids unnecessary requests
So if two components call the same query with the same arguments, only one request happens.
But real apps need more control — and that’s where refetching options come in.
Manual Refetch: “Fetch Again, Now”
Every useGetSomethingQuery hook gives you a refetch function.
const { data, refetch } = useGetUsersQuery()
You can call it anytime:
<button onClick={refetch}>Refresh</button>
When should you use this?
Refresh button
Pull-to-refresh
After closing a modal
When you decide data is outdated
Simple. Explicit. Reliable.
Refetch When the Component Mounts
Sometimes you want fresh data every time a screen opens.
useGetUsersQuery(undefined, {
refetchOnMountOrArgChange: true,
})
Now:
Each mount = new request
Each argument change = new request
Even better: time-based freshness
refetchOnMountOrArgChange: 30
This means:
“Refetch only if the cached data is older than 30 seconds.”
This feels very similar to stale time in React Query.
Refetch When User Comes Back to the Tab
Ever notice apps refreshing when you return to them?
RTK Query can do that too.
refetchOnFocus: true
When the browser tab regains focus → data refreshes.
⚠️ Don’t forget to enable listeners:
setupListeners(store.dispatch)
Refetch When Internet Comes Back
Perfect for mobile users or unstable connections.
refetchOnReconnect: true
When the network reconnects → data refetches automatically.
Polling: Refetch on a Timer
Need live-ish updates?
pollingInterval: 10000
This refetches every 10 seconds while the component is mounted.
You can even control it dynamically:
pollingInterval: isLive ? 5000 : 0
Skipping a Query (Fetch Only When Ready)
Sometimes you don’t have the data needed to fetch yet.
Using skip
useGetUserQuery(userId, { skip: !userId })
Better: skipToken
useGetUserQuery(userId ?? skipToken)
This completely prevents the request until the condition is met.
The Most Important Feature: Cache Invalidation (Magic ✨)
Instead of manually refetching, let RTK Query handle it automatically.
Example:
getUsers: builder.query({
query: () => '/users',
providesTags: ['Users'],
})
Now when you mutate:
addUser: builder.mutation({
query: (body) => ({
url: '/users',
method: 'POST',
body,
}),
invalidatesTags: ['Users'],
})
What happens?
➡️ RTK Query automatically refetches getUsers
No refetch()
No hacks
No guessing
This is the recommended way to keep data fresh.
Cache Lifetime (Not Refetching)
This controls how long data stays in memory, not when it refetches.
keepUnusedDataFor: 60
Meaning:
“Keep cached data for 60 seconds after no component is using it.”
This helps performance — but doesn’t trigger a new fetch.
Force Refetch (Advanced Use)
Sometimes you want full control.
forceRefetch({ currentArg, previousArg }) {
return currentArg !== previousArg
}
Useful for:
Pagination
Filters
Complex argument logic
A Simple Mental Model
Think of RTK Query like this:
Queries fetch and cache data
Options decide when to refetch
Tags decide what should refetch
Mutations trigger automatic updates
Manual refetch is your escape hatch
