T
TanStack•12mo ago
rare-sapphire

Long waiting time for queryFn to run

Hi, I'm experiencing a strange issue with react-query. When the useQuery function is mounted, and I can see it registered in the devtools, it takes several milliseconds (1500 - 3400) to run queryFn. My code:
const { data, refetch } = useQuery<Stop>({
queryKey: ["stop", city, stop],
queryFn: () => fetchStop(city, stop, limit),
});
const { data, refetch } = useQuery<Stop>({
queryKey: ["stop", city, stop],
queryFn: () => fetchStop(city, stop, limit),
});
and queryClient options:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnMount: true,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
},
},
});
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnMount: true,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
},
},
});
38 Replies
sunny-green
sunny-green•12mo ago
I don't understand the video. Where is the 3 second delay? I guess you have already tried to make a log statement inside the queryFn before you call fetchStop to see when it gets executed ?
rare-sapphire
rare-sapphireOP•12mo ago
look at chrome devtools and query devtools, you can see that request pop ups several miliseconds later and i did that with console
sunny-green
sunny-green•12mo ago
and the log is also delayed ?
rare-sapphire
rare-sapphireOP•12mo ago
yes and fetchStop is simple fetch but with auth headers
rare-sapphire
rare-sapphireOP•12mo ago
No description
rare-sapphire
rare-sapphireOP•12mo ago
it's exactly 1 second which is a bit too long
sunny-green
sunny-green•12mo ago
so you've done this?
console.log('render', Date.now())
const { data, refetch } = useQuery<Stop>({
queryKey: ["stop", city, stop],
queryFn: () => {
console.log('queryFn', Date.now())
return fetchStop(city, stop, limit),
}
});
console.log('render', Date.now())
const { data, refetch } = useQuery<Stop>({
queryKey: ["stop", city, stop],
queryFn: () => {
console.log('queryFn', Date.now())
return fetchStop(city, stop, limit),
}
});
and there is 1 second between those ?
rare-sapphire
rare-sapphireOP•12mo ago
almost exactly
No description
sunny-green
sunny-green•12mo ago
hm, could be rendering related, as the fetch is triggered after render. Can you make a minimal return after the useQuery, like an empty div or so to check ? but then it wouldn't show up as fetching in the devtools either. There isn't any code between those lines though. We set the query to fetching state (which is what the devtools show), and then we create a retryer and start fetching, which calls the queryFn.
rare-sapphire
rare-sapphireOP•12mo ago
like this?
rare-sapphire
rare-sapphireOP•12mo ago
No description
sunny-green
sunny-green•12mo ago
yeah
rare-sapphire
rare-sapphireOP•12mo ago
still the same
No description
sunny-green
sunny-green•12mo ago
this should be impossible 😂 okay query devtools show multiple observers. Are there other components using the same query? We need to trim it down to a minimum until those logs match up
rare-sapphire
rare-sapphireOP•12mo ago
i can change querykey on main component oh that was it
rare-sapphire
rare-sapphireOP•12mo ago
No description
rare-sapphire
rare-sapphireOP•12mo ago
but it's weird
rare-sapphire
rare-sapphireOP•12mo ago
that's the other observers
No description
No description
sunny-green
sunny-green•12mo ago
multiple observers is fine, but only one of them is triggering the fetch. Maybe there is something blocking going on in one of the other components? again, try trimming it down by returning empty divs / remove other hook calls etc
sunny-green
sunny-green•12mo ago
in isolation, theres like 5ms difference between render and fetch
No description
rare-sapphire
rare-sapphireOP•12mo ago
still the same
No description
No description
No description
No description
sunny-green
sunny-green•12mo ago
so which of the 3 do you have to comment out to get better numbers?
rare-sapphire
rare-sapphireOP•12mo ago
those with no queryFn i can try giving them queryFn
sunny-green
sunny-green•12mo ago
aah I didn't see that. no queryFn is bad I see what's happening the one without queryFn probably renders first, that initiates the fetch. It doesn't have a queryFn, so it errors out with "no queryFn found". Then retryDelay kicks in, and 1second later, it starts to work That's also why you see it in fetching state in the devtools
rare-sapphire
rare-sapphireOP•12mo ago
ohhhh that makes sense
sunny-green
sunny-green•12mo ago
why would you make a query without a queryFn 😂
rare-sapphire
rare-sapphireOP•12mo ago
well it works on production
sunny-green
sunny-green•12mo ago
coincidentally maybe
rare-sapphire
rare-sapphireOP•12mo ago
until I fully stopped using redux
sunny-green
sunny-green•12mo ago
okay just don't do it please. extract the key + fn to a query factory, use queryOptions and use those options in all places: https://tkdodo.eu/blog/the-query-options-api
The Query Options API
v5 brought a new, powerful API, especially if you're using React Query with TypeScript...
rare-sapphire
rare-sapphireOP•12mo ago
okay, i have used this:
No description
rare-sapphire
rare-sapphireOP•12mo ago
thank you for help
sunny-green
sunny-green•12mo ago
eh, but why? this isn't reactive, so the component won't re-render on its own if new data comes in what's wrong with calling useQuery with the same key and the same function as in other places? if you're worried about too many refetches, just set staleTime
rare-sapphire
rare-sapphireOP•12mo ago
the main component has limit param that is not accessible from any other file so there is no other option that useQuery to get latest data
sunny-green
sunny-green•12mo ago
yeah I've seen the limit param. If it's used in the queryFn, it also needs to go into the queryKey otherwise, changes in limit won't trigger refetches so in general, all dependencies for a query need to be in the key (we have a lint rule for that), and they need to be available wherever you want to use the query
rare-sapphire
rare-sapphireOP•12mo ago
Can I keep the queryKey as it is, add queryFn to the child components with a default value for limit, and then have the main component manage the actual limit and perform refetch()?
sunny-green
sunny-green•12mo ago
I can't rule out stale closure problems with that approach. If the limit can change, why not add it to the key? You'll also overwrite cache entries with different limits this way ...
rare-sapphire
rare-sapphireOP•12mo ago
that's the point, if limit goes up I don't need to access old requests with lower limits

Did you find this page helpful?