Skip to content

Commit 956a33f

Browse files
committed
fix: notify query cache on stale
1 parent 1eb4d00 commit 956a33f

File tree

8 files changed

+45
-31
lines changed

8 files changed

+45
-31
lines changed

src/core/config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ export const DEFAULT_CONFIG: ReactQueryConfig = {
6666
},
6767
}
6868

69+
export function getDefaultReactQueryConfig() {
70+
return {
71+
shared: { ...DEFAULT_CONFIG.shared },
72+
queries: { ...DEFAULT_CONFIG.queries },
73+
mutations: { ...DEFAULT_CONFIG.mutations },
74+
}
75+
}
76+
6977
export function mergeReactQueryConfigs(
7078
a: ReactQueryConfig,
7179
b: ReactQueryConfig

src/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { getDefaultReactQueryConfig } from './config'
12
export { queryCache, queryCaches, makeQueryCache } from './queryCache'
23
export { setFocusHandler } from './setFocusHandler'
34
export { setOnlineHandler } from './setOnlineHandler'

src/core/query.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,15 @@ export interface QueryState<TResult, TError> {
3232
data?: TResult
3333
error: TError | null
3434
failureCount: number
35-
fetchedCount: number
3635
isError: boolean
37-
isFetched: boolean
3836
isFetching: boolean
3937
isFetchingMore: IsFetchingMoreValue
4038
isIdle: boolean
4139
isLoading: boolean
4240
isSuccess: boolean
4341
status: QueryStatus
4442
throwInErrorBoundary?: boolean
43+
updateCount: number
4544
updatedAt: number
4645
}
4746

@@ -594,12 +593,11 @@ function getDefaultState<TResult, TError>(
594593
return {
595594
...getStatusProps(initialStatus),
596595
error: null,
597-
isFetched: Boolean(config.initialFetched),
598596
isFetching: initialStatus === QueryStatus.Loading,
599597
isFetchingMore: false,
600598
failureCount: 0,
601-
fetchedCount: config.initialFetched ? 1 : 0,
602599
data: initialData,
600+
updateCount: 0,
603601
updatedAt: Date.now(),
604602
canFetchMore: hasMorePages(config, initialData),
605603
}
@@ -633,11 +631,10 @@ export function queryReducer<TResult, TError>(
633631
...getStatusProps(QueryStatus.Success),
634632
data: action.data,
635633
error: null,
636-
fetchedCount: state.fetchedCount + 1,
637-
isFetched: true,
638634
isFetching: false,
639635
isFetchingMore: false,
640636
canFetchMore: action.canFetchMore,
637+
updateCount: state.updateCount + 1,
641638
updatedAt: action.updatedAt ?? Date.now(),
642639
failureCount: 0,
643640
}
@@ -646,10 +643,9 @@ export function queryReducer<TResult, TError>(
646643
...state,
647644
...getStatusProps(QueryStatus.Error),
648645
error: action.error,
649-
fetchedCount: state.fetchedCount + 1,
650-
isFetched: true,
651646
isFetching: false,
652647
isFetchingMore: false,
648+
updateCount: state.updateCount + 1,
653649
failureCount: state.failureCount + 1,
654650
throwInErrorBoundary: true,
655651
}

src/core/queryCache.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
Updater,
33
deepIncludes,
4-
functionalUpdate,
54
getQueryArgs,
65
isDocumentVisible,
76
isPlainObject,
@@ -336,19 +335,7 @@ export class QueryCache {
336335
updater: Updater<TResult | undefined, TResult>,
337336
config?: QueryConfig<TResult, TError>
338337
) {
339-
const resolvedConfig = this.getResolvedQueryConfig(queryKey, config)
340-
const query = this.getQueryByHash<TResult, TError>(resolvedConfig.queryHash)
341-
342-
if (query) {
343-
query.setData(updater)
344-
return
345-
}
346-
347-
this.createQuery({
348-
initialFetched: true,
349-
initialData: functionalUpdate(updater, undefined),
350-
...resolvedConfig,
351-
})
338+
this.buildQuery(queryKey, config).setData(updater)
352339
}
353340
}
354341

src/core/queryObserver.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ export class QueryObserver<TResult, TError> {
1818
private currentResult!: QueryResult<TResult, TError>
1919
private previousQueryResult?: QueryResult<TResult, TError>
2020
private listener?: UpdateListener<TResult, TError>
21-
private initialFetchedCount: number
21+
private initialUpdateCount: number
2222
private staleTimeoutId?: number
2323
private refetchIntervalId?: number
2424

2525
constructor(config: ResolvedQueryConfig<TResult, TError>) {
2626
this.config = config
27-
this.initialFetchedCount = 0
27+
this.initialUpdateCount = 0
2828

2929
// Bind exposed methods
3030
this.clear = this.clear.bind(this)
@@ -161,6 +161,7 @@ export class QueryObserver<TResult, TError> {
161161
if (!this.currentResult.isStale) {
162162
this.currentResult = { ...this.currentResult, isStale: true }
163163
this.notify()
164+
this.config.queryCache.notifyGlobalListeners(this.currentQuery)
164165
}
165166
}, timeout)
166167
}
@@ -229,7 +230,7 @@ export class QueryObserver<TResult, TError> {
229230

230231
// When the query has not been fetched yet and this is the initial render,
231232
// determine the staleness based on the initialStale or existence of initial data.
232-
if (!currentResult && !state.isFetched) {
233+
if (!currentResult && state.updateCount === 0) {
233234
if (typeof config.initialStale === 'function') {
234235
isStale = config.initialStale()
235236
} else if (typeof config.initialStale === 'boolean') {
@@ -249,8 +250,8 @@ export class QueryObserver<TResult, TError> {
249250
error: state.error,
250251
failureCount: state.failureCount,
251252
fetchMore: this.fetchMore,
252-
isFetched: state.isFetched,
253-
isFetchedAfterMount: state.fetchedCount > this.initialFetchedCount,
253+
isFetched: state.updateCount > 0,
254+
isFetchedAfterMount: state.updateCount > this.initialUpdateCount,
254255
isFetching: state.isFetching,
255256
isFetchingMore: state.isFetchingMore,
256257
isPreviousData,
@@ -284,7 +285,7 @@ export class QueryObserver<TResult, TError> {
284285

285286
this.previousQueryResult = this.currentResult
286287
this.currentQuery = query
287-
this.initialFetchedCount = query.state.fetchedCount
288+
this.initialUpdateCount = query.state.updateCount
288289
this.updateResult()
289290

290291
if (this.listener) {

src/core/tests/queryCache.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ describe('queryCache', () => {
544544
expect(query.state).toMatchObject({
545545
data: 'data',
546546
isLoading: false,
547-
isFetched: true,
547+
updateCount: 1,
548548
})
549549
})
550550

@@ -578,7 +578,7 @@ describe('queryCache', () => {
578578
expect(query.state).toMatchObject({
579579
data: undefined,
580580
isLoading: false,
581-
isFetched: true,
581+
updateCount: 1,
582582
})
583583
})
584584

src/core/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ export interface BaseQueryConfig<TResult, TError = unknown, TData = TResult> {
4949
queryKeySerializerFn?: QueryKeySerializerFunction
5050
queryFnParamsFilter?: (args: ArrayQueryKey) => ArrayQueryKey
5151
initialData?: TResult | InitialDataFunction<TResult>
52-
initialFetched?: boolean
5352
infinite?: true
5453
/**
5554
* Set this to `false` to disable structural sharing between query results.

src/react/tests/useQuery.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,28 @@ describe('useQuery', () => {
829829
)
830830
})
831831

832+
it('should notify query cache when a query becomes stale', async () => {
833+
const key = queryKey()
834+
const states: QueryResult<string>[] = []
835+
const fn = jest.fn()
836+
837+
const unsubscribe = queryCache.subscribe(fn)
838+
839+
function Page() {
840+
const state = useQuery(key, () => 'test', {
841+
staleTime: 10,
842+
})
843+
states.push(state)
844+
return null
845+
}
846+
847+
render(<Page />)
848+
849+
await waitForMs(20)
850+
unsubscribe()
851+
expect(fn).toHaveBeenCalledTimes(3)
852+
})
853+
832854
it('should not re-render when a query status changes and notifyOnStatusChange is false', async () => {
833855
const key = queryKey()
834856
const states: QueryResult<string>[] = []

0 commit comments

Comments
 (0)