Skip to content

Commit 6540a41

Browse files
feat(core): callback for retryOnMount (#10515)
* feat(core): callback for retryOnMount * ci: apply automated fixes * fix: vue --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 61b9763 commit 6540a41

14 files changed

Lines changed: 146 additions & 51 deletions

File tree

.changeset/silver-places-pick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/query-core': minor
3+
---
4+
5+
feat(query-core): accept callback function for retryOnMount

docs/framework/react/reference/useQuery.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ const {
8686
- If set to a `number`, e.g. `3`, failed queries will retry until the failed query count meets that number.
8787
- If set to a function, it will be called with `failureCount` (starting at `0` for the first retry) and `error` to determine if a retry should be attempted.
8888
- defaults to `3` on the client and `0` on the server
89-
- `retryOnMount: boolean`
90-
- If set to `false`, the query will not be retried on mount if it contains an error. Defaults to `true`.
89+
- `retryOnMount: boolean | (query: Query) => boolean`
90+
- If set to `false`, the query will not be retried on mount if it contains an error and has no data. Defaults to `true`.
91+
- If set to a function, the function will be executed with the query to compute the value.
9192
- `retryDelay: number | (retryAttempt: number, error: TError) => number`
9293
- This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds.
9394
- A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff.

docs/framework/solid/reference/useQuery.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,9 @@ function App() {
277277
- If `true`, failed queries will retry infinitely.
278278
- If set to a `number`, e.g. `3`, failed queries will retry until the failed query count meets that number.
279279
- defaults to `3` on the client and `0` on the server
280-
- ##### `retryOnMount: boolean`
281-
- If set to `false`, the query will not be retried on mount if it contains an error. Defaults to `true`.
280+
- ##### `retryOnMount: boolean | (query: Query) => boolean`
281+
- If set to `false`, the query will not be retried on mount if it contains an error and has no data. Defaults to `true`.
282+
- If set to a function, the function will be executed with the query to compute the value.
282283
- ##### `retryDelay: number | (retryAttempt: number, error: TError) => number`
283284
- This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds.
284285
- A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff.

packages/preact-query/src/__tests__/QueryResetErrorBoundary.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ describe('QueryErrorResetBoundary', () => {
753753
}),
754754
retry: false,
755755
throwOnError: true,
756-
retryOnMount: true,
756+
retryOnMount: () => true,
757757
},
758758
],
759759
})
@@ -818,7 +818,7 @@ describe('QueryErrorResetBoundary', () => {
818818
return 'data'
819819
}),
820820
retry: false,
821-
retryOnMount: true,
821+
retryOnMount: () => true,
822822
},
823823
],
824824
})

packages/preact-query/src/__tests__/useQuery.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4919,7 +4919,7 @@ describe('useQuery', () => {
49194919
queryFn,
49204920
enabled,
49214921
retry: false,
4922-
retryOnMount: false,
4922+
retryOnMount: () => false,
49234923
refetchOnMount: false,
49244924
refetchOnWindowFocus: false,
49254925
})
@@ -4979,7 +4979,7 @@ describe('useQuery', () => {
49794979
return 'data'
49804980
},
49814981
retry: false,
4982-
retryOnMount: false,
4982+
retryOnMount: () => false,
49834983
refetchOnMount: false,
49844984
refetchOnWindowFocus: false,
49854985
})
@@ -5033,7 +5033,7 @@ describe('useQuery', () => {
50335033
queryFn: () =>
50345034
sleep(10).then(() => Promise.reject<unknown>(new Error('Error'))),
50355035
retry: false,
5036-
retryOnMount: false,
5036+
retryOnMount: () => false,
50375037
refetchOnMount: false,
50385038
refetchOnWindowFocus: false,
50395039
})
@@ -6012,7 +6012,7 @@ describe('useQuery', () => {
60126012
queryKey: key,
60136013
queryFn,
60146014
retry: false,
6015-
retryOnMount: false,
6015+
retryOnMount: () => false,
60166016
})
60176017

60186018
states.push(state)
@@ -6433,7 +6433,7 @@ describe('useQuery', () => {
64336433
? () => sleep(10).then(() => Promise.resolve('data'))
64346434
: skipToken,
64356435
retry: false,
6436-
retryOnMount: false,
6436+
retryOnMount: () => false,
64376437
refetchOnMount: false,
64386438
refetchOnWindowFocus: false,
64396439
})

packages/query-core/src/query.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
ensureQueryFn,
33
noop,
44
replaceData,
5-
resolveEnabled,
5+
resolveQueryBoolean,
66
resolveStaleTime,
77
skipToken,
88
timeUntilStale,
@@ -271,7 +271,8 @@ export class Query<
271271

272272
isActive(): boolean {
273273
return this.observers.some(
274-
(observer) => resolveEnabled(observer.options.enabled, this) !== false,
274+
(observer) =>
275+
resolveQueryBoolean(observer.options.enabled, this) !== false,
275276
)
276277
}
277278

packages/query-core/src/queryObserver.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
isValidTimeout,
99
noop,
1010
replaceData,
11-
resolveEnabled,
11+
resolveQueryBoolean,
1212
resolveStaleTime,
1313
shallowEqualObjects,
1414
timeUntilStale,
@@ -153,7 +153,7 @@ export class QueryObserver<
153153
this.options.enabled !== undefined &&
154154
typeof this.options.enabled !== 'boolean' &&
155155
typeof this.options.enabled !== 'function' &&
156-
typeof resolveEnabled(this.options.enabled, this.#currentQuery) !==
156+
typeof resolveQueryBoolean(this.options.enabled, this.#currentQuery) !==
157157
'boolean'
158158
) {
159159
throw new Error(
@@ -197,8 +197,8 @@ export class QueryObserver<
197197
if (
198198
mounted &&
199199
(this.#currentQuery !== prevQuery ||
200-
resolveEnabled(this.options.enabled, this.#currentQuery) !==
201-
resolveEnabled(prevOptions.enabled, this.#currentQuery) ||
200+
resolveQueryBoolean(this.options.enabled, this.#currentQuery) !==
201+
resolveQueryBoolean(prevOptions.enabled, this.#currentQuery) ||
202202
resolveStaleTime(this.options.staleTime, this.#currentQuery) !==
203203
resolveStaleTime(prevOptions.staleTime, this.#currentQuery))
204204
) {
@@ -211,8 +211,8 @@ export class QueryObserver<
211211
if (
212212
mounted &&
213213
(this.#currentQuery !== prevQuery ||
214-
resolveEnabled(this.options.enabled, this.#currentQuery) !==
215-
resolveEnabled(prevOptions.enabled, this.#currentQuery) ||
214+
resolveQueryBoolean(this.options.enabled, this.#currentQuery) !==
215+
resolveQueryBoolean(prevOptions.enabled, this.#currentQuery) ||
216216
nextRefetchInterval !== this.#currentRefetchInterval)
217217
) {
218218
this.#updateRefetchInterval(nextRefetchInterval)
@@ -394,7 +394,7 @@ export class QueryObserver<
394394

395395
if (
396396
environmentManager.isServer() ||
397-
resolveEnabled(this.options.enabled, this.#currentQuery) === false ||
397+
resolveQueryBoolean(this.options.enabled, this.#currentQuery) === false ||
398398
!isValidTimeout(this.#currentRefetchInterval) ||
399399
this.#currentRefetchInterval === 0
400400
) {
@@ -589,7 +589,7 @@ export class QueryObserver<
589589
isStale: isStale(query, options),
590590
refetch: this.refetch,
591591
promise: this.#currentThenable,
592-
isEnabled: resolveEnabled(options.enabled, query) !== false,
592+
isEnabled: resolveQueryBoolean(options.enabled, query) !== false,
593593
}
594594

595595
const nextResult = result as QueryObserverResult<TData, TError>
@@ -750,9 +750,12 @@ function shouldLoadOnMount(
750750
options: QueryObserverOptions<any, any, any, any>,
751751
): boolean {
752752
return (
753-
resolveEnabled(options.enabled, query) !== false &&
753+
resolveQueryBoolean(options.enabled, query) !== false &&
754754
query.state.data === undefined &&
755-
!(query.state.status === 'error' && options.retryOnMount === false)
755+
!(
756+
query.state.status === 'error' &&
757+
resolveQueryBoolean(options.retryOnMount, query) === false
758+
)
756759
)
757760
}
758761

@@ -775,7 +778,7 @@ function shouldFetchOn(
775778
(typeof options)['refetchOnReconnect'],
776779
) {
777780
if (
778-
resolveEnabled(options.enabled, query) !== false &&
781+
resolveQueryBoolean(options.enabled, query) !== false &&
779782
resolveStaleTime(options.staleTime, query) !== 'static'
780783
) {
781784
const value = typeof field === 'function' ? field(query) : field
@@ -793,7 +796,7 @@ function shouldFetchOptionally(
793796
): boolean {
794797
return (
795798
(query !== prevQuery ||
796-
resolveEnabled(prevOptions.enabled, query) === false) &&
799+
resolveQueryBoolean(prevOptions.enabled, query) === false) &&
797800
(!options.suspense || query.state.status !== 'error') &&
798801
isStale(query, options)
799802
)
@@ -804,7 +807,7 @@ function isStale(
804807
options: QueryObserverOptions<any, any, any, any, any>,
805808
): boolean {
806809
return (
807-
resolveEnabled(options.enabled, query) !== false &&
810+
resolveQueryBoolean(options.enabled, query) !== false &&
808811
query.isStaleByTime(resolveStaleTime(options.staleTime, query))
809812
)
810813
}

packages/query-core/src/types.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export type StaleTimeFunction<
110110
| StaleTime
111111
| ((query: Query<TQueryFnData, TError, TData, TQueryKey>) => StaleTime)
112112

113-
export type Enabled<
113+
export type QueryBooleanOption<
114114
TQueryFnData = unknown,
115115
TError = DefaultError,
116116
TData = TQueryFnData,
@@ -326,7 +326,7 @@ export interface QueryObserverOptions<
326326
* Accepts a boolean or function that returns a boolean.
327327
* Defaults to `true`.
328328
*/
329-
enabled?: Enabled<TQueryFnData, TError, TQueryData, TQueryKey>
329+
enabled?: QueryBooleanOption<TQueryFnData, TError, TQueryData, TQueryKey>
330330
/**
331331
* The time in milliseconds after data is considered stale.
332332
* If set to `Infinity`, the data will never be considered stale.
@@ -391,9 +391,10 @@ export interface QueryObserverOptions<
391391
) => boolean | 'always')
392392
/**
393393
* If set to `false`, the query will not be retried on mount if it contains an error.
394+
* If set to a function, the function will be executed with the query to compute the value.
394395
* Defaults to `true`.
395396
*/
396-
retryOnMount?: boolean
397+
retryOnMount?: QueryBooleanOption<TQueryFnData, TError, TQueryData, TQueryKey>
397398
/**
398399
* If set, the component will only re-render if any of the listed properties change.
399400
* When set to `['data', 'error']`, the component will only re-render when the `data` or `error` properties change.

packages/query-core/src/utils.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { timeoutManager } from './timeoutManager'
22
import type {
33
DefaultError,
4-
Enabled,
54
FetchStatus,
65
MutationKey,
76
MutationStatus,
7+
QueryBooleanOption,
88
QueryFunction,
99
QueryKey,
1010
QueryOptions,
@@ -126,16 +126,18 @@ export function resolveStaleTime<
126126
return typeof staleTime === 'function' ? staleTime(query) : staleTime
127127
}
128128

129-
export function resolveEnabled<
129+
export function resolveQueryBoolean<
130130
TQueryFnData = unknown,
131131
TError = DefaultError,
132132
TData = TQueryFnData,
133133
TQueryKey extends QueryKey = QueryKey,
134134
>(
135-
enabled: undefined | Enabled<TQueryFnData, TError, TData, TQueryKey>,
135+
option:
136+
| undefined
137+
| QueryBooleanOption<TQueryFnData, TError, TData, TQueryKey>,
136138
query: Query<TQueryFnData, TError, TData, TQueryKey>,
137139
): boolean | undefined {
138-
return typeof enabled === 'function' ? enabled(query) : enabled
140+
return typeof option === 'function' ? option(query) : option
139141
}
140142

141143
export function matchQuery(

packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ describe('QueryErrorResetBoundary', () => {
829829
}),
830830
retry: false,
831831
throwOnError: true,
832-
retryOnMount: true,
832+
retryOnMount: () => true,
833833
},
834834
],
835835
})
@@ -894,7 +894,7 @@ describe('QueryErrorResetBoundary', () => {
894894
return 'data'
895895
}),
896896
retry: false,
897-
retryOnMount: true,
897+
retryOnMount: () => true,
898898
},
899899
],
900900
})

0 commit comments

Comments
 (0)