My application looked good.
It felt fast.
Everything seemed to be working correctly.
So I thought my new currency changing feature was finished.
But one day, I opened the browser's Network tab just to see what was actually happening behind the UI.
And I noticed something strange.
I went to my Settings page.
The application fetched the currency from the database.
Fine.
Then I went to the Dashboard.
Then I came back to Settings.
Another request.
I tried it again.
Another request.
And again.
Another request.
I started thinking:
"Why is my application asking the database for the same information again and again?"
The UI was fast, but the Network tab showed me something I couldn't see from the UI.
That was the beginning of a small but important lesson about server state, caching, and React Query.
What was actually happening?
My currency was stored in Supabase.
For example:
currency_code = "TRY"
When Settings needed the currency, React Query fetched it:
React Query → Supabase
↓
TRY
But when I left the Settings page and came back, the query ran again.
At first, I thought:
"If I'm using React Query, shouldn't it remember the data?"
Yes — React Query does cache data.
But there was something I didn't understand yet:
Having data in the cache doesn't necessarily mean React Query considers that data fresh.
That distinction was the important part.
What is staleTime?
I discovered staleTime.
The default behavior I was dealing with was effectively:
staleTime: 0
This doesn't mean the cached data disappears.
It means React Query considers the data stale immediately.
And "stale" doesn't mean:
"This data is wrong."
It means:
"This data might be old, so I should be willing to check the server again."
That made much more sense to me.
For example, suppose React Query gets:
TRY
It can keep:
Cache = TRY
but still consider it stale.
When I return to the page, React Query can say:
"I already have TRY, but it's stale. I'll check Supabase again."
That's why I was seeing another request in the Network tab.
So I tried staleTime: Infinity
For currency, the value isn't something that changes every few seconds.
A salon's currency might stay:
TRY
for a very long time.
So I changed the query configuration to:
staleTime: Infinity
Now I'm basically telling React Query:
"Once you fetch this currency, consider it fresh. Don't automatically treat it as stale."
So the flow becomes:
First visit
↓
Fetch currency
↓
TRY
↓
Cache
Leave Settings
↓
Go somewhere else
↓
Come back
Use cached TRY
↓
No unnecessary request
That was the first piece of the puzzle.
Then I discovered gcTime
Just when I thought I understood caching, I found another option:
gcTime
At first, this confused me even more.
But the idea is actually simple.
staleTime asks:
"How long should I consider this data fresh?"
gcTime asks:
"How long should I keep unused data in the cache?"
They are different.
Think about it like this:
staleTime
↓
Is my cached data fresh?
gcTime
↓
Should I keep this unused cached data?
I used:
gcTime: Infinity
for this configuration because I wanted the cached currency to remain available rather than being garbage-collected while the application is being used.
What about "session"?
This was another thing I initially misunderstood.
When developers say something is kept "for the session," it doesn't necessarily mean React Query has a special thing called a session.
A session can simply mean the period during which I'm using the application.
For example:
Open application
↓
Use Dashboard
↓
Open Settings
↓
Change currency
↓
Visit Clients
↓
Return to Settings
↓
Continue using application
That's the current period of using my application.
There is also an authentication session, such as the session Supabase Auth uses to know that I'm logged in.
Those are related ideas, but they're not the same thing as React Query's cache.
That distinction was important for me to understand.
One more thing: invalidateQueries
I also had to understand why I shouldn't automatically invalidate the currency query after changing it.
Imagine I change:
TRY → EUR
The database confirms:
EUR
I already know the new value.
So instead of saying:
"The cache might be wrong. Go ask the database again."
I can update the cache directly:
queryClient.setQueryData(["currency"], "EUR");
Now:
Database = EUR
Cache = EUR
UI = EUR
Everything is already synchronized.
invalidateQueries() is still very useful when I don't know the new server state and want React Query to check again.
But when I already have the confirmed new value, setQueryData() makes more sense.
The small lesson that became a bigger one
The most interesting part wasn't actually fixing the request.
It was realizing that the UI doesn't tell me everything about my application.
My application looked fast.
It worked.
There were no visible errors.
But when I opened the Network tab, I discovered that I was making unnecessary requests.
That changed how I think about frontend development.
Now I don't only ask:
"Does my feature work?"
I also ask:
"What is my application actually doing behind the UI?"
Sometimes opening the Network tab for five minutes can teach you more than staring at your component for an hour.
And for me, this small currency feature became my introduction to an important React Query concept:
Fetching data is only half of the problem. Knowing when to fetch it again is another part of building a good application.
Top comments (0)