Is there a way to refetch a query with new parameters?
Hi
I'm using tRPC in a Next.js app and I have a button that a user can click to get the latest data from the server. By default this data is cached in the server because the query is expensive. I've added an optional param/input in my query that looks like this:
So when
{ skipCache: true }
is set, the user can bypass the cache and get the latest data. I'm feeling a bit lost however when it comes to the implementation itself. I can't find anything in the docs regarding refetching with new/updated params.
Is this something that's possible?Solution:Jump to solution
What you can do is just to have a skipCache state and pass this to your useQuery.
```tsx
const [skipCache, setSkipCache] = useState(false);
...
18 Replies
If you invalidate the query it will refetch https://trpc.io/docs/client/react/useUtils#query-invalidation
useUtils | tRPC
useUtils is a hook that gives you access to helpers that let you manage the cached data of the queries you execute via @trpc/react-query. These helpers are actually thin wrappers around @tanstack/react-query's queryClient methods. If you want more in-depth information about options and usage patterns for useContext helpers than what we provide h...
so
Also you shouldn't skip the cache, it's better to set the time till the data is stale. If the data is stale useQuery will automatically refetch when it's run. You can also set the refetchInterval, so that the data gets refetched every n milliseconds given
https://tanstack.com/query/latest/docs/react/reference/useQuery
useQuery | TanStack Query Docs
const {
data,
thanks i've tried this before, but such is the feature. if a user wants the latest data it makes for bad ux to make them wait a certain time. also as mentioned it's an expensive query so it should only be done every now and then, which is why the cache i have on the server lasts 15 mins. is there no workaround at all for this?
Ah sorry, had misread your question. I still don't fully understand however. What's the problem with the invalidate method?
so i've used invalidation before, but the reason it doesn't work in my case is that it uses the same query details to make another request to the server. there's no way for me to explicitly state in the invalidation that this specific request is supposed to have a new set of parameters.
i was thinking of maybe creating a new route in my server to invalidate the cache and return new data
but that leads to 2 routes doing almost the same thing. they'll both return the same data, but one does with cache and one without
invalidate()
without input invalidates all queries, regardless of input. So invalidate()
will invalidate even a query like trpc.private.guilds()
and trpc.private.guilds({skipCache: true})
. If you only want to invalidate the query where you used a specific input like trpc.private.guilds({skipCache: true})
then you can call utils.private.guilds.invalidate({skipCache: true})
Or do you mean that you first want to do it without cache, and then with cache?the other way around actually
when the page is first loaded, the data that is fetched should be from the cache (if it's available in the server). but the user will now have the chance to fetch the latest data by clicking a button. this button is supposed to invalidate the cache in the server and return the most up to date data
imagine a discord bot dashboard where you have a list of servers
once a user is in this page, say they create a new server in discord but now that server is not part of the list in the web app because it's still using the cache which will last another 15 mins
the refresh button will give them the option to fetch the latest array of servers
Solution
What you can do is just to have a skipCache state and pass this to your useQuery.
alright so i've tried this approach too and there is one slight issue. let me explain.
everything works well until the
handleRefresh
function has stopped calling.
say the user wants to refresh the list of guilds once again. the skipCache
state is now stuck at true
and handleRefresh
won't do anything anymore when called
changing it back to false
at the end of the handleRefresh
function doesn't seem to do anything either because of how react handles state changesWhy would handleRefresh not do anything after the first refetch?
invalidate()
will always force a refetch.you're definitely right there, but there is still an issue of requests sent on behalf of tRPC when focusing on the window. i like that feature but when focusing back on the window it'll send new requests. but now it'll send with
skipCache
set to true
because the state still hasn't changed back to falseAnd you want to keep refetchOnWindowFocus enabled?
it would be nice to have that, but if i can keep that turned off i believe that fixes the issue right? tRPC doesn't send any other requests automatically i'm guessing?
Yes, setting that to false disables that behavior.
If you do want to keep it enabled, you might just need to use the queryClient manually and then update the queryKey yourself manually like you would when doing an optimistic update. If you understand what I mean.
i think for now i'll disable
refetchOnWindowFocus
. in case i find a reason for it to be enabled i'll have to do a little more research on using the queryClient xD
i believe that solves the issue for meI'm sure it's a case of me trying to use it incorrectly, but . . .
Depending on state to trigger a refetch seems "wrong". 🤔 Is there no "freedom" to manually
refetch
with different/additional params as allowed by the actual endpoint? Is there a reason we're "handcuffed" in this way? Admittedly, the primary reason I'm using TRPC in the first place is for "ease of validation" and a bit of typesafety, but if I'm forced to rely on state for various individual params of a potentially larger params object, it might be "better" to just use an old school RESTful setup. 😢It’s just not a use-case tRPC solves, you can use the trpcClient and React Query manually if you want more freedom. Or just use the client standalone.