fix(query-core): never schedule gc timers on the server by A-Raphie · Pull Request #12135 · TanStack/query · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/query-core/src/__tests__/query.test.tsx
29 changes: 29 additions & 0 deletions packages/query-core/src/__tests__/queryObserver.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1589,6 +1589,35 @@ describe('queryObserver', () => {
expect(result.data).toBe('data')
})

it('should fetch a query that was rebuilt without a queryFn via fetchOptimistic options', async () => {
const key = queryKey()
const cache = queryClient.getQueryCache()

// The observer is first bound to a query with a queryFn...
const observer = new QueryObserver(queryClient, {
queryKey: key,
queryFn: () => 'old',
})

// ...the query is removed (e.g. removeQueries on logout)...
const removed = cache.find({ queryKey: key })!
await cache.remove(removed)

// ...and broadcastQueryClient rebuilds it from { queryKey, queryHash }
// only, without a queryFn. The observer is still bound to the removed
// query, so the rebuilt query has no observers and no options when the
// suspending render calls fetchOptimistic.
cache.build(queryClient, { queryKey: key })

const result = await observer.fetchOptimistic({
queryKey: key,
queryFn: () => 'data',
})

expect(result.status).toBe('success')
expect(result.data).toBe('data')
})

it('should resolve fetchOptimistic with cached data while the fetch continues', async () => {
const key = queryKey()

Expand Down
7 changes: 6 additions & 1 deletion packages/query-core/src/queryObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,12 @@ export class QueryObserver<

return Promise.race([
query
.fetch()
// Pass the options so a query that already existed without a queryFn
// (e.g. rebuilt from a broadcast message or hydrated) still fetches
// with this observer's queryFn - `build` does not apply options to an
// existing query, and `fetch()` would otherwise only fall back to
// already-attached observers, of which there are none yet here.
.fetch(defaultedOptions)
.then(() => {
const result = this.createResult(query, defaultedOptions)
// Settle the subscriber promise so both branches always settle.
Expand Down
8 changes: 7 additions & 1 deletion packages/query-core/src/removable.ts