55 isValidTimeout ,
66 noop ,
77} from './utils'
8- import { QueryResult , ResolvedQueryConfig , QueryStatus } from './types'
8+ import type { QueryResult , ResolvedQueryConfig } from './types'
99import type { Query , Action , FetchMoreOptions , RefetchOptions } from './query'
1010
1111export type UpdateListener < TResult , TError > = (
@@ -19,12 +19,14 @@ export class QueryObserver<TResult, TError> {
1919 private currentResult ! : QueryResult < TResult , TError >
2020 private previousQueryResult ?: QueryResult < TResult , TError >
2121 private listener ?: UpdateListener < TResult , TError >
22+ private isStale : boolean
2223 private initialUpdateCount : number
2324 private staleTimeoutId ?: number
2425 private refetchIntervalId ?: number
2526
2627 constructor ( config : ResolvedQueryConfig < TResult , TError > ) {
2728 this . config = config
29+ this . isStale = true
2830 this . initialUpdateCount = 0
2931
3032 // Bind exposed methods
@@ -128,9 +130,9 @@ export class QueryObserver<TResult, TError> {
128130
129131 private optionalFetch ( ) : void {
130132 if (
131- this . config . enabled && // Don't auto refetch if disabled
133+ this . config . enabled && // Only fetch if enabled
134+ this . isStale && // Only fetch if stale
132135 ! ( this . config . suspense && this . currentResult . isFetched ) && // Don't refetch if in suspense mode and the data is already fetched
133- this . currentResult . isStale && // Only refetch if stale
134136 ( this . config . refetchOnMount || this . currentQuery . observers . length === 1 )
135137 ) {
136138 this . fetch ( )
@@ -148,7 +150,7 @@ export class QueryObserver<TResult, TError> {
148150
149151 this . clearStaleTimeout ( )
150152
151- if ( this . currentResult . isStale || ! isValidTimeout ( this . config . staleTime ) ) {
153+ if ( this . isStale || ! isValidTimeout ( this . config . staleTime ) ) {
152154 return
153155 }
154156
@@ -157,8 +159,9 @@ export class QueryObserver<TResult, TError> {
157159 const timeout = Math . max ( timeUntilStale , 0 )
158160
159161 this . staleTimeoutId = setTimeout ( ( ) => {
160- if ( ! this . currentResult . isStale ) {
161- this . currentResult = { ...this . currentResult , isStale : true }
162+ if ( ! this . isStale ) {
163+ this . isStale = true
164+ this . updateResult ( )
162165 this . notify ( )
163166 this . config . queryCache . notifyGlobalListeners ( this . currentQuery )
164167 }
@@ -208,40 +211,23 @@ export class QueryObserver<TResult, TError> {
208211 }
209212
210213 private updateResult ( ) : void {
211- const { currentQuery, currentResult , previousQueryResult, config } = this
214+ const { currentQuery, previousQueryResult, config } = this
212215 const { state } = currentQuery
213216 let { data, status, updatedAt } = state
214217 let isPreviousData = false
215218
216219 // Keep previous data if needed
217220 if (
218221 config . keepPreviousData &&
219- ( state . status === QueryStatus . Idle ||
220- state . status === QueryStatus . Loading ) &&
221- previousQueryResult ?. status === QueryStatus . Success
222+ state . isInitialData &&
223+ previousQueryResult ?. isSuccess
222224 ) {
223225 data = previousQueryResult . data
224226 updatedAt = previousQueryResult . updatedAt
225227 status = previousQueryResult . status
226228 isPreviousData = true
227229 }
228230
229- let isStale
230-
231- // When the query has not been fetched yet and this is the initial render,
232- // determine the staleness based on the initialStale or existence of initial data.
233- if ( ! currentResult && state . isInitialData ) {
234- if ( typeof config . initialStale === 'function' ) {
235- isStale = config . initialStale ( )
236- } else if ( typeof config . initialStale === 'boolean' ) {
237- isStale = config . initialStale
238- } else {
239- isStale = typeof state . data === 'undefined'
240- }
241- } else {
242- isStale = currentQuery . isStaleByTime ( config . staleTime )
243- }
244-
245231 this . currentResult = {
246232 ...getStatusProps ( status ) ,
247233 canFetchMore : state . canFetchMore ,
@@ -256,22 +242,16 @@ export class QueryObserver<TResult, TError> {
256242 isFetchingMore : state . isFetchingMore ,
257243 isInitialData : state . isInitialData ,
258244 isPreviousData,
259- isStale,
245+ isStale : this . isStale ,
260246 refetch : this . refetch ,
261247 updatedAt,
262248 }
263249 }
264250
265251 private updateQuery ( ) : void {
252+ const config = this . config
266253 const prevQuery = this . currentQuery
267254
268- // Remove the initial data when there is an existing query
269- // because this data should not be used for a new query
270- const config =
271- this . config . keepPreviousData && prevQuery
272- ? { ...this . config , initialData : undefined }
273- : this . config
274-
275255 let query = config . queryCache . getQueryByHash < TResult , TError > (
276256 config . queryHash
277257 )
@@ -287,6 +267,22 @@ export class QueryObserver<TResult, TError> {
287267 this . previousQueryResult = this . currentResult
288268 this . currentQuery = query
289269 this . initialUpdateCount = query . state . updateCount
270+
271+ // Update stale state on query switch
272+ if ( query . state . isInitialData ) {
273+ if ( config . keepPreviousData && prevQuery ) {
274+ this . isStale = true
275+ } else if ( typeof config . initialStale === 'function' ) {
276+ this . isStale = config . initialStale ( )
277+ } else if ( typeof config . initialStale === 'boolean' ) {
278+ this . isStale = config . initialStale
279+ } else {
280+ this . isStale = typeof query . state . data === 'undefined'
281+ }
282+ } else {
283+ this . isStale = query . isStaleByTime ( config . staleTime )
284+ }
285+
290286 this . updateResult ( )
291287
292288 if ( this . listener ) {
@@ -296,16 +292,20 @@ export class QueryObserver<TResult, TError> {
296292 }
297293
298294 onQueryUpdate ( action : Action < TResult , TError > ) : void {
295+ const { config } = this
299296 const { type } = action
300297
298+ // Update stale state on success or error
299+ if ( type === 2 || type === 3 ) {
300+ this . isStale = this . currentQuery . isStaleByTime ( config . staleTime )
301+ }
302+
301303 // Store current result and get new result
302304 const prevResult = this . currentResult
303305 this . updateResult ( )
306+ const currentResult = this . currentResult
304307
305- const { currentResult, config } = this
306-
307- // We need to check the action because the state could have
308- // transitioned from success to success in case of `setQueryData`.
308+ // Trigger callbacks and timers on success or error
309309 if ( type === 2 ) {
310310 config . onSuccess ?.( currentResult . data ! )
311311 config . onSettled ?.( currentResult . data ! , null )
0 commit comments