Skip to content

Commit

Permalink
fix(core): don't consider queries as enabled if they have no observer…
Browse files Browse the repository at this point in the history
…s and have never fetched (successfully or erroneously) (#8161)

it's very likely that this used to be a disabled observer; one other case would be canceling a query while you were initially fetching it, but this is a weird corner case that brings all sorts of troubles

additionally, we can check for the queryFn being a skipToken; even if we have data in the cache, when the queryFn is currently set to skipToken, this is means we never want to see this query fetch
  • Loading branch information
TkDodo authored Oct 10, 2024
1 parent e3aca98 commit 5228e51
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 1 deletion.
40 changes: 40 additions & 0 deletions packages/query-core/src/__tests__/queryClient.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,46 @@ describe('queryClient', () => {
expect(queryFn2).toHaveBeenCalledTimes(2)
})

test('should not refetch disabled inactive queries even if "refetchType" is "all', async () => {
const queryFn = vi
.fn<(...args: Array<unknown>) => string>()
.mockReturnValue('data1')
const observer = new QueryObserver(queryClient, {
queryKey: queryKey(),
queryFn: queryFn,
staleTime: Infinity,
enabled: false,
})
const unsubscribe = observer.subscribe(() => undefined)
unsubscribe()
await queryClient.invalidateQueries({
refetchType: 'all',
})
expect(queryFn).toHaveBeenCalledTimes(0)
})

test('should not refetch inactive queries that have a skipToken queryFn even if "refetchType" is "all', async () => {
const key = queryKey()
const observer = new QueryObserver(queryClient, {
queryKey: key,
queryFn: skipToken,
staleTime: Infinity,
})

queryClient.setQueryData(key, 'data1')

const unsubscribe = observer.subscribe(() => undefined)
unsubscribe()

expect(queryClient.getQueryState(key)?.dataUpdateCount).toBe(1)

await queryClient.invalidateQueries({
refetchType: 'all',
})

expect(queryClient.getQueryState(key)?.dataUpdateCount).toBe(1)
})

test('should cancel ongoing fetches if cancelRefetch option is set (default value)', async () => {
const key = queryKey()
const abortFn = vi.fn()
Expand Down
10 changes: 9 additions & 1 deletion packages/query-core/src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
noop,
replaceData,
resolveEnabled,
skipToken,
timeUntilStale,
} from './utils'
import { notifyManager } from './notifyManager'
Expand Down Expand Up @@ -256,7 +257,14 @@ export class Query<
}

isDisabled(): boolean {
return this.getObserversCount() > 0 && !this.isActive()
if (this.getObserversCount() > 0) {
return !this.isActive()
}
// if a query has no observers, it should still be considered disabled if it never attempted a fetch
return (
this.options.queryFn === skipToken ||
this.state.dataUpdateCount + this.state.errorUpdateCount === 0
)
}

isStale(): boolean {
Expand Down

0 comments on commit 5228e51

Please sign in to comment.