TanStack / query

🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.
https://tanstack.com/query
MIT License
42.76k stars 2.92k forks source link

`fetchQuery` returns stale data when used with `createPersister` #8075

Open fa-sharp opened 2 months ago

fa-sharp commented 2 months ago

Describe the bug

I noticed that when using createPersister and then calling queryClient.fetchQuery, it will always return stale data from the persisted cache (if there's no data in the local cache).

Taking a look at the createPersister code, I can see that it signals if the query is stale, but it still returns the stale data. While this makes sense in a useQuery context, it doesn't make sense when using a procedural function like queryClient.fetchQuery, where we expect it to fetch the latest data if the cache is stale.

This makes it difficult to use the persister in a non-React context, e.g. in an extension service worker, where we might want to make procedural calls to fetchQuery to update some data in the background. I'm using a very questionable hack right now to get around this, calling fetchQuery two times. The first time, it returns the stale persisted data and loads it into the local cache. The second time, it actually runs the query function, as fetchQuery now detects stale data in the local cache. This has the desired effect of fetching the latest data, and automatically saving it to the persister (indexedDB in my case).

const staleData = await queryClient.fetchQuery(...)
await new Promise((r) => setTimeout(r, 100)); // this is necessary because the local cache isn't loaded immediately
const freshData = await queryClient.fetchQuery(...)

Your minimal, reproducible example

https://codesandbox.io/p/sandbox/loving-brook-9ln67f

Steps to reproduce

  1. Click on the "Fetch query" button a couple times. The counter will advance, as expected. The button is calling fetchQuery, and the counter data is also persisted to localStorage using createPersister.
  2. Click on "Clear local cache," which will clear React Query's local cache using queryClient.clear()
  3. Click "Fetch query" again. This time the counter will not advance, as fetchQuery is returning the stale data from createPersister, even though the staleTime is set to 10ms.
  4. If you click "Fetch query" one more time, this time the counter will advance, as fetchQuery now detects stale data in the local cache.

Expected behavior

I expect fetchQuery to run the query function and return the latest data, if it sees that the data from the persister is stale.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

macOS, Chrome 128

Tanstack Query adapter

react-query

TanStack Query version

v5.56.2

TypeScript version

v5.6.2

Additional context

This is tangentially related to the discussions in #6310 and #7677

0xd8d commented 1 month ago

I also experience this issue with ensureQueryData and revalidateIfStale set to true. It doesn't revalidate on page load.