Skip to content

Commit 8a0ae88

Browse files
committed
feat: determine staleness locally instead of globally
1 parent 8f6bdf3 commit 8a0ae88

File tree

5 files changed

+213
-136
lines changed

5 files changed

+213
-136
lines changed

src/core/query.ts

Lines changed: 17 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export interface QueryState<TResult, TError> {
4444
isFetchingMore: IsFetchingMoreValue
4545
isIdle: boolean
4646
isLoading: boolean
47-
isStale: boolean
4847
isSuccess: boolean
4948
status: QueryStatus
5049
throwInErrorBoundary?: boolean
@@ -66,7 +65,6 @@ export interface RefetchOptions {
6665

6766
export enum ActionType {
6867
Failed = 'Failed',
69-
MarkStale = 'MarkStale',
7068
Fetch = 'Fetch',
7169
Success = 'Success',
7270
Error = 'Error',
@@ -76,10 +74,6 @@ interface FailedAction {
7674
type: ActionType.Failed
7775
}
7876

79-
interface MarkStaleAction {
80-
type: ActionType.MarkStale
81-
}
82-
8377
interface FetchAction {
8478
type: ActionType.Fetch
8579
isFetchingMore?: IsFetchingMoreValue
@@ -89,7 +83,6 @@ interface SuccessAction<TResult> {
8983
type: ActionType.Success
9084
data: TResult | undefined
9185
canFetchMore?: boolean
92-
isStale: boolean
9386
}
9487

9588
interface ErrorAction<TError> {
@@ -101,7 +94,6 @@ export type Action<TResult, TError> =
10194
| ErrorAction<TError>
10295
| FailedAction
10396
| FetchAction
104-
| MarkStaleAction
10597
| SuccessAction<TResult>
10698

10799
// CLASS
@@ -136,7 +128,6 @@ export class Query<TResult, TError> {
136128

137129
activateTimeouts(): void {
138130
this.enableTimeouts = true
139-
this.rescheduleStaleTimeout()
140131
this.rescheduleGarbageCollection()
141132
}
142133

@@ -150,45 +141,6 @@ export class Query<TResult, TError> {
150141
this.notifyGlobalListeners(this)
151142
}
152143

153-
private rescheduleStaleTimeout(): void {
154-
if (isServer) {
155-
return
156-
}
157-
158-
this.clearStaleTimeout()
159-
160-
if (
161-
!this.enableTimeouts ||
162-
this.state.isStale ||
163-
this.state.status !== QueryStatus.Success ||
164-
this.config.staleTime === Infinity
165-
) {
166-
return
167-
}
168-
169-
const staleTime = this.config.staleTime || 0
170-
let timeout = staleTime
171-
if (this.state.updatedAt) {
172-
const timeElapsed = Date.now() - this.state.updatedAt
173-
const timeUntilStale = staleTime - timeElapsed
174-
timeout = Math.max(timeUntilStale, 0)
175-
}
176-
177-
this.staleTimeout = setTimeout(() => {
178-
this.invalidate()
179-
}, timeout)
180-
}
181-
182-
invalidate(): void {
183-
this.clearStaleTimeout()
184-
185-
if (this.state.isStale) {
186-
return
187-
}
188-
189-
this.dispatch({ type: ActionType.MarkStale })
190-
}
191-
192144
private rescheduleGarbageCollection(): void {
193145
if (isServer) {
194146
return
@@ -230,7 +182,7 @@ export class Query<TResult, TError> {
230182

231183
private clearTimersObservers(): void {
232184
this.observers.forEach(observer => {
233-
observer.clearRefetchInterval()
185+
observer.clearTimers()
234186
})
235187
}
236188

@@ -264,20 +216,15 @@ export class Query<TResult, TError> {
264216
data = prevData
265217
}
266218

267-
const isStale = this.config.staleTime === 0
268-
269219
// Try to determine if more data can be fetched
270220
const canFetchMore = hasMorePages(this.config, data)
271221

272222
// Set data and mark it as cached
273223
this.dispatch({
274224
type: ActionType.Success,
275225
data,
276-
isStale,
277226
canFetchMore,
278227
})
279-
280-
this.rescheduleStaleTimeout()
281228
}
282229

283230
clear(): void {
@@ -293,12 +240,22 @@ export class Query<TResult, TError> {
293240
return this.observers.some(observer => observer.config.enabled)
294241
}
295242

243+
isStale(): boolean {
244+
return this.observers.some(observer => observer.isStale())
245+
}
246+
247+
isStaleByTime(staleTime = 0): boolean {
248+
const { isSuccess, updatedAt } = this.state
249+
return !isSuccess || updatedAt + staleTime <= Date.now()
250+
}
251+
296252
onWindowFocus(): void {
297253
if (
298-
this.state.isStale &&
299254
this.observers.some(
300255
observer =>
301-
observer.config.enabled && observer.config.refetchOnWindowFocus
256+
observer.isStale() &&
257+
observer.config.enabled &&
258+
observer.config.refetchOnWindowFocus
302259
)
303260
) {
304261
this.fetch()
@@ -308,10 +265,11 @@ export class Query<TResult, TError> {
308265

309266
onOnline(): void {
310267
if (
311-
this.state.isStale &&
312268
this.observers.some(
313269
observer =>
314-
observer.config.enabled && observer.config.refetchOnReconnect
270+
observer.isStale() &&
271+
observer.config.enabled &&
272+
observer.config.refetchOnReconnect
315273
)
316274
) {
317275
this.fetch()
@@ -628,12 +586,6 @@ function getDefaultState<TResult, TError>(
628586

629587
const hasInitialData = typeof initialData !== 'undefined'
630588

631-
const isStale =
632-
!config.enabled ||
633-
(typeof config.initialStale === 'function'
634-
? config.initialStale()
635-
: config.initialStale ?? !hasInitialData)
636-
637589
const initialStatus = hasInitialData
638590
? QueryStatus.Success
639591
: config.enabled
@@ -647,9 +599,8 @@ function getDefaultState<TResult, TError>(
647599
isFetching: initialStatus === QueryStatus.Loading,
648600
isFetchingMore: false,
649601
failureCount: 0,
650-
isStale,
651602
data: initialData,
652-
updatedAt: hasInitialData ? Date.now() : 0,
603+
updatedAt: Date.now(),
653604
canFetchMore: hasMorePages(config, initialData),
654605
}
655606
}
@@ -664,11 +615,6 @@ export function queryReducer<TResult, TError>(
664615
...state,
665616
failureCount: state.failureCount + 1,
666617
}
667-
case ActionType.MarkStale:
668-
return {
669-
...state,
670-
isStale: true,
671-
}
672618
case ActionType.Fetch:
673619
const status =
674620
typeof state.data !== 'undefined'
@@ -687,7 +633,6 @@ export function queryReducer<TResult, TError>(
687633
...getStatusProps(QueryStatus.Success),
688634
data: action.data,
689635
error: null,
690-
isStale: action.isStale,
691636
isFetched: true,
692637
isFetching: false,
693638
isFetchingMore: false,
@@ -703,7 +648,6 @@ export function queryReducer<TResult, TError>(
703648
isFetched: true,
704649
isFetching: false,
705650
isFetchingMore: false,
706-
isStale: true,
707651
failureCount: state.failureCount + 1,
708652
throwInErrorBoundary: true,
709653
}

src/core/queryCache.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ export class QueryCache {
189189
}
190190
}
191191

192-
return query.invalidate()
192+
return undefined
193193
})
194194
)
195195
} catch (err) {
@@ -305,7 +305,7 @@ export class QueryCache {
305305
let query
306306
try {
307307
query = this.buildQuery<TResult, TError>(queryKey, configWithoutRetry)
308-
if (options?.force || query.state.isStale) {
308+
if (options?.force || query.isStaleByTime(config.staleTime)) {
309309
await query.fetch()
310310
}
311311
return query.state.data

0 commit comments

Comments
 (0)