SWR pattern within one query
I have two data sources for the same query/API endpoint. One cached, potentially stale but very quick to access, and another one, remote and fresh, etc. The idea is I would be OK with stale data but would refresh it in the background from the fresh data source. I wouldn't need to show a loading state as long as there's stale data around.
The behavior I'd want on an empty QueryClient store:
1. Load from the fast data store
2. Render with it (contentful)
3. If the above response is stale, load from the remote data store
4. Re-render with the latest data
And if I have data in the QueryClient already:
1. Render immediately using the most fresh version available, regardless of what data store it came from
2. If the data was stale, load from the remote data store
3. Re-render with the latest data
On fetch error, I would want to know about the error state but also use the most recent version of data I have.
I've been thinking about how to best realize this with react-query. I could make some custom
useQuerySWR hook that would run two different queries (but always at least one enabled query) and mix in the output depending on what's available and if the cached data is stale.
Or if I wanted to fold it into the same query from the perspective of react-query, I could possibly capture the QueryClient in my queryFn, return cached data from the promise but also spawn another promise against the fresh data source (if the cached version was stale) and call setQueryData directly. But then I'd run into trying to make this work with all the timing parameters and query state that react-query tracks.
I've also considered placeholderData but I didn't grasp the full lifecycle of it, I think it gets reset when queryFn throws an exception?
Is there a paved path to something like this? Ideally I'd just use a battle tested pattern and get the benefits for free, just like with everything else thanks to react-query 😄 .5 Replies
dependent-tan•7mo ago
you'd need to code that yourself, but it's not that hard to do within the
queryFn, as we provide the queryClient and the queryKey to it::
You just need to know how isFresh(data) is going to look, I guess it means inspecting headers? Has nothing to do with react-query thoughforeign-sapphireOP•7mo ago
Thanks.
So setQueryData would reset all the timers wrt staleTime, right? Anytime a queryFn resolves or setQueryData is called, it resets the age of that query?
I'm thinking would it be possible to set a very high staleTime (like one hour) and then inspect the age of available data at the start of
queryFn to decide where to route the request?
Maybe something like
But then I'd need some method of telling QueryClient about the age of the data I just resolved from queryFn and I haven't seen anything like that.
If what I'm describing could work, I think the advantage would be that react-query would re-fetch immediately when the data goes stale, right?
For example:
1. store is empty
2. I fetch through the fast store and tell react-query this data is 45 seconds old
3. 15 seconds pass
4. react query calls my queryFn again, this time loading from the remote data store.
If I don't have that level of control in react-query, then I'm probably going to rely on the browser cache/maybe a service worker and then react-query will refetch all the time but 99% of these would be served from the browser cache
I found queryClient.getQueryState(queryKey).dateUpdatedAt but no way to set it, so I don't think my approach would work. Probably easiest to implement Cache-Control properly and let react-query attempt re-fetching periodicallydependent-tan•7mo ago
So setQueryData would reset all the timers wrt staleTime, right? Anytime a queryFn resolves or setQueryData is called, it resets the age of that query?yes because it's computed based on
dataUpdatedAt, which gets set when data gets into the cache (no matter how)
I found queryClient.getQueryState(queryKey).dateUpdatedAt but no way to set ityou can set it with
setQueryData:
It's there to tell react query: this data is of a certain age. It defaults to Date.now()foreign-sapphireOP•7mo ago
Oh very cool. But it is an undocumented API, so would it be OK to use it or is that as good as unstable & unsupported? https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetquerydata
I've already implemented proper HTTP SWR semantics in my Cloudflare Worker, so react-query doing periodic refetches in the background is either served from the browser's cache or the edge's. But I might still use this API if it's stable. Could I also set the staleTime for that specific query in
setQueryData?QueryClient | TanStack Query Docs
QueryClient The QueryClient can be used to interact with a cache: tsx import { QueryClient } from '@tanstack/react-query' const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime:...
dependent-tan•7mo ago
It's missing docs, please add it 🙂
It's very much supported
You can't set staleTime because a query has no staleTime. Every observer can have a staleTime from its own point of view