@tanstack/query-core 5.0.0-alpha.5 → 5.0.0-alpha.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lib/focusManager.d.ts +2 -1
- package/build/lib/focusManager.d.ts.map +1 -0
- package/build/lib/focusManager.js.map +1 -1
- package/build/lib/focusManager.mjs.map +1 -1
- package/build/lib/hydration.d.ts +3 -6
- package/build/lib/hydration.d.ts.map +1 -0
- package/build/lib/hydration.js +4 -18
- package/build/lib/hydration.js.map +1 -1
- package/build/lib/hydration.mjs +4 -18
- package/build/lib/hydration.mjs.map +1 -1
- package/build/lib/index.d.ts +5 -3
- package/build/lib/index.d.ts.map +1 -0
- package/build/lib/infiniteQueryBehavior.d.ts +1 -0
- package/build/lib/infiniteQueryBehavior.d.ts.map +1 -0
- package/build/lib/infiniteQueryBehavior.js +1 -0
- package/build/lib/infiniteQueryBehavior.js.map +1 -1
- package/build/lib/infiniteQueryBehavior.mjs +1 -0
- package/build/lib/infiniteQueryBehavior.mjs.map +1 -1
- package/build/lib/infiniteQueryObserver.d.ts +2 -1
- package/build/lib/infiniteQueryObserver.d.ts.map +1 -0
- package/build/lib/infiniteQueryObserver.js.map +1 -1
- package/build/lib/infiniteQueryObserver.mjs.map +1 -1
- package/build/lib/mutation.d.ts +2 -1
- package/build/lib/mutation.d.ts.map +1 -0
- package/build/lib/mutation.js.map +1 -1
- package/build/lib/mutation.mjs.map +1 -1
- package/build/lib/mutationCache.d.ts +3 -2
- package/build/lib/mutationCache.d.ts.map +1 -0
- package/build/lib/mutationCache.js +5 -4
- package/build/lib/mutationCache.js.map +1 -1
- package/build/lib/mutationCache.mjs +5 -4
- package/build/lib/mutationCache.mjs.map +1 -1
- package/build/lib/mutationObserver.d.ts +2 -1
- package/build/lib/mutationObserver.d.ts.map +1 -0
- package/build/lib/mutationObserver.js +1 -1
- package/build/lib/mutationObserver.js.map +1 -1
- package/build/lib/mutationObserver.mjs +1 -1
- package/build/lib/mutationObserver.mjs.map +1 -1
- package/build/lib/notifyManager.d.ts +4 -3
- package/build/lib/notifyManager.d.ts.map +1 -0
- package/build/lib/notifyManager.js.map +1 -1
- package/build/lib/notifyManager.mjs.map +1 -1
- package/build/lib/onlineManager.d.ts +2 -1
- package/build/lib/onlineManager.d.ts.map +1 -0
- package/build/lib/onlineManager.js.map +1 -1
- package/build/lib/onlineManager.mjs.map +1 -1
- package/build/lib/queriesObserver.d.ts +14 -6
- package/build/lib/queriesObserver.d.ts.map +1 -0
- package/build/lib/queriesObserver.js +39 -16
- package/build/lib/queriesObserver.js.map +1 -1
- package/build/lib/queriesObserver.mjs +39 -16
- package/build/lib/queriesObserver.mjs.map +1 -1
- package/build/lib/query.d.ts +6 -4
- package/build/lib/query.d.ts.map +1 -0
- package/build/lib/query.js +2 -2
- package/build/lib/query.js.map +1 -1
- package/build/lib/query.mjs +2 -2
- package/build/lib/query.mjs.map +1 -1
- package/build/lib/queryCache.d.ts +3 -3
- package/build/lib/queryCache.d.ts.map +1 -0
- package/build/lib/queryCache.js +8 -5
- package/build/lib/queryCache.js.map +1 -1
- package/build/lib/queryCache.mjs +8 -5
- package/build/lib/queryCache.mjs.map +1 -1
- package/build/lib/queryClient.d.ts +2 -2
- package/build/lib/queryClient.d.ts.map +1 -0
- package/build/lib/queryClient.js +19 -13
- package/build/lib/queryClient.js.map +1 -1
- package/build/lib/queryClient.mjs +19 -13
- package/build/lib/queryClient.mjs.map +1 -1
- package/build/lib/queryObserver.d.ts +5 -7
- package/build/lib/queryObserver.d.ts.map +1 -0
- package/build/lib/queryObserver.js +15 -27
- package/build/lib/queryObserver.js.map +1 -1
- package/build/lib/queryObserver.mjs +16 -28
- package/build/lib/queryObserver.mjs.map +1 -1
- package/build/lib/removable.d.ts +1 -0
- package/build/lib/removable.d.ts.map +1 -0
- package/build/lib/removable.js.map +1 -1
- package/build/lib/removable.mjs.map +1 -1
- package/build/lib/retryer.d.ts +5 -4
- package/build/lib/retryer.d.ts.map +1 -0
- package/build/lib/retryer.js +2 -0
- package/build/lib/retryer.js.map +1 -1
- package/build/lib/retryer.mjs +2 -0
- package/build/lib/retryer.mjs.map +1 -1
- package/build/lib/subscribable.d.ts +3 -2
- package/build/lib/subscribable.d.ts.map +1 -0
- package/build/lib/subscribable.js +4 -4
- package/build/lib/subscribable.js.map +1 -1
- package/build/lib/subscribable.mjs +4 -4
- package/build/lib/subscribable.mjs.map +1 -1
- package/build/lib/tests/focusManager.test.d.ts +1 -0
- package/build/lib/tests/focusManager.test.d.ts.map +1 -0
- package/build/lib/tests/hydration.test.d.ts +1 -0
- package/build/lib/tests/hydration.test.d.ts.map +1 -0
- package/build/lib/tests/infiniteQueryBehavior.test.d.ts +1 -0
- package/build/lib/tests/infiniteQueryBehavior.test.d.ts.map +1 -0
- package/build/lib/tests/infiniteQueryObserver.test.d.ts +1 -0
- package/build/lib/tests/infiniteQueryObserver.test.d.ts.map +1 -0
- package/build/lib/tests/mutationCache.test.d.ts +1 -0
- package/build/lib/tests/mutationCache.test.d.ts.map +1 -0
- package/build/lib/tests/mutationObserver.test.d.ts +1 -0
- package/build/lib/tests/mutationObserver.test.d.ts.map +1 -0
- package/build/lib/tests/mutations.test.d.ts +1 -0
- package/build/lib/tests/mutations.test.d.ts.map +1 -0
- package/build/lib/tests/notifyManager.test.d.ts +1 -0
- package/build/lib/tests/notifyManager.test.d.ts.map +1 -0
- package/build/lib/tests/onlineManager.test.d.ts +1 -0
- package/build/lib/tests/onlineManager.test.d.ts.map +1 -0
- package/build/lib/tests/queriesObserver.test.d.ts +1 -0
- package/build/lib/tests/queriesObserver.test.d.ts.map +1 -0
- package/build/lib/tests/query.test.d.ts +1 -0
- package/build/lib/tests/query.test.d.ts.map +1 -0
- package/build/lib/tests/queryCache.test.d.ts +1 -0
- package/build/lib/tests/queryCache.test.d.ts.map +1 -0
- package/build/lib/tests/queryClient.test.d.ts +1 -0
- package/build/lib/tests/queryClient.test.d.ts.map +1 -0
- package/build/lib/tests/queryObserver.test.d.ts +1 -0
- package/build/lib/tests/queryObserver.test.d.ts.map +1 -0
- package/build/lib/tests/utils.d.ts +3 -2
- package/build/lib/tests/utils.d.ts.map +1 -0
- package/build/lib/tests/utils.test.d.ts +1 -0
- package/build/lib/tests/utils.test.d.ts.map +1 -0
- package/build/lib/types.d.ts +35 -45
- package/build/lib/types.d.ts.map +1 -0
- package/build/lib/utils.d.ts +4 -3
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js.map +1 -1
- package/build/lib/utils.mjs.map +1 -1
- package/package.json +8 -6
- package/src/hydration.ts +18 -37
- package/src/index.ts +3 -4
- package/src/infiniteQueryBehavior.ts +1 -0
- package/src/mutationCache.ts +4 -4
- package/src/mutationObserver.ts +1 -1
- package/src/queriesObserver.ts +74 -24
- package/src/query.ts +7 -5
- package/src/queryCache.ts +5 -8
- package/src/queryClient.ts +20 -20
- package/src/queryObserver.ts +43 -51
- package/src/subscribable.ts +5 -5
- package/src/tests/hydration.test.tsx +7 -3
- package/src/tests/infiniteQueryBehavior.test.tsx +9 -0
- package/src/tests/query.test.tsx +1 -1
- package/src/tests/queryCache.test.tsx +1 -19
- package/src/tests/queryClient.test.tsx +39 -3
- package/src/tests/queryObserver.test.tsx +121 -0
- package/src/types.ts +15 -20
- package/build/lib/focusManager.esm.js +0 -71
- package/build/lib/focusManager.esm.js.map +0 -1
- package/build/lib/hydration.esm.js +0 -98
- package/build/lib/hydration.esm.js.map +0 -1
- package/build/lib/index.esm.js +0 -14
- package/build/lib/index.esm.js.map +0 -1
- package/build/lib/infiniteQueryBehavior.esm.js +0 -125
- package/build/lib/infiniteQueryBehavior.esm.js.map +0 -1
- package/build/lib/infiniteQueryObserver.esm.js +0 -75
- package/build/lib/infiniteQueryObserver.esm.js.map +0 -1
- package/build/lib/mutation.esm.js +0 -234
- package/build/lib/mutation.esm.js.map +0 -1
- package/build/lib/mutationCache.esm.js +0 -82
- package/build/lib/mutationCache.esm.js.map +0 -1
- package/build/lib/mutationObserver.esm.js +0 -96
- package/build/lib/mutationObserver.esm.js.map +0 -1
- package/build/lib/notifyManager.esm.js +0 -89
- package/build/lib/notifyManager.esm.js.map +0 -1
- package/build/lib/onlineManager.esm.js +0 -73
- package/build/lib/onlineManager.esm.js.map +0 -1
- package/build/lib/queriesObserver.esm.js +0 -136
- package/build/lib/queriesObserver.esm.js.map +0 -1
- package/build/lib/query.esm.js +0 -420
- package/build/lib/query.esm.js.map +0 -1
- package/build/lib/queryCache.esm.js +0 -101
- package/build/lib/queryCache.esm.js.map +0 -1
- package/build/lib/queryClient.esm.js +0 -277
- package/build/lib/queryClient.esm.js.map +0 -1
- package/build/lib/queryObserver.esm.js +0 -440
- package/build/lib/queryObserver.esm.js.map +0 -1
- package/build/lib/removable.esm.js +0 -29
- package/build/lib/removable.esm.js.map +0 -1
- package/build/lib/retryer.esm.js +0 -150
- package/build/lib/retryer.esm.js.map +0 -1
- package/build/lib/subscribable.esm.js +0 -26
- package/build/lib/subscribable.esm.js.map +0 -1
- package/build/lib/utils.esm.js +0 -227
- package/build/lib/utils.esm.js.map +0 -1
- package/build/umd/index.development.js +0 -2682
- package/build/umd/index.development.js.map +0 -1
- package/build/umd/index.production.js +0 -2
- package/build/umd/index.production.js.map +0 -1
package/src/queryCache.ts
CHANGED
|
@@ -27,7 +27,6 @@ interface QueryCacheConfig {
|
|
|
27
27
|
error: DefaultError | null,
|
|
28
28
|
query: Query<unknown, unknown, unknown>,
|
|
29
29
|
) => void
|
|
30
|
-
createStore?: () => QueryStore
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
interface NotifyEventQueryAdded extends NotifyEvent {
|
|
@@ -95,7 +94,7 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
|
|
|
95
94
|
|
|
96
95
|
constructor(public config: QueryCacheConfig = {}) {
|
|
97
96
|
super()
|
|
98
|
-
this.#queries =
|
|
97
|
+
this.#queries = new Map<string, Query>()
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
build<TQueryFnData, TError, TData, TQueryKey extends QueryKey>(
|
|
@@ -176,13 +175,11 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
|
|
|
176
175
|
find<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData>(
|
|
177
176
|
filters: WithRequired<QueryFilters, 'queryKey'>,
|
|
178
177
|
): Query<TQueryFnData, TError, TData> | undefined {
|
|
179
|
-
|
|
180
|
-
filters.exact = true
|
|
181
|
-
}
|
|
178
|
+
const defaultedFilters = { exact: true, ...filters }
|
|
182
179
|
|
|
183
|
-
return this.getAll().find((query) =>
|
|
184
|
-
|
|
185
|
-
|
|
180
|
+
return this.getAll().find((query) =>
|
|
181
|
+
matchQuery(defaultedFilters, query),
|
|
182
|
+
) as Query<TQueryFnData, TError, TData> | undefined
|
|
186
183
|
}
|
|
187
184
|
|
|
188
185
|
findAll(filters: QueryFilters = {}): Query[] {
|
package/src/queryClient.ts
CHANGED
|
@@ -25,6 +25,8 @@ import type {
|
|
|
25
25
|
ResetOptions,
|
|
26
26
|
SetDataOptions,
|
|
27
27
|
DefaultError,
|
|
28
|
+
CancelOptions,
|
|
29
|
+
DefaultedQueryObserverOptions,
|
|
28
30
|
} from './types'
|
|
29
31
|
import type { QueryState } from './query'
|
|
30
32
|
import { QueryCache } from './queryCache'
|
|
@@ -33,7 +35,6 @@ import { focusManager } from './focusManager'
|
|
|
33
35
|
import { onlineManager } from './onlineManager'
|
|
34
36
|
import { notifyManager } from './notifyManager'
|
|
35
37
|
import { infiniteQueryBehavior } from './infiniteQueryBehavior'
|
|
36
|
-
import type { CancelOptions, DefaultedQueryObserverOptions } from './types'
|
|
37
38
|
|
|
38
39
|
// TYPES
|
|
39
40
|
|
|
@@ -212,14 +213,12 @@ export class QueryClient {
|
|
|
212
213
|
filters: QueryFilters = {},
|
|
213
214
|
cancelOptions: CancelOptions = {},
|
|
214
215
|
): Promise<void> {
|
|
215
|
-
|
|
216
|
-
cancelOptions.revert = true
|
|
217
|
-
}
|
|
216
|
+
const defaultedCancelOptions = { revert: true, ...cancelOptions }
|
|
218
217
|
|
|
219
218
|
const promises = notifyManager.batch(() =>
|
|
220
219
|
this.#queryCache
|
|
221
220
|
.findAll(filters)
|
|
222
|
-
.map((query) => query.cancel(
|
|
221
|
+
.map((query) => query.cancel(defaultedCancelOptions)),
|
|
223
222
|
)
|
|
224
223
|
|
|
225
224
|
return Promise.all(promises).then(noop).catch(noop)
|
|
@@ -249,25 +248,26 @@ export class QueryClient {
|
|
|
249
248
|
filters: RefetchQueryFilters = {},
|
|
250
249
|
options?: RefetchOptions,
|
|
251
250
|
): Promise<void> {
|
|
251
|
+
const fetchOptions = {
|
|
252
|
+
...options,
|
|
253
|
+
cancelRefetch: options?.cancelRefetch ?? true,
|
|
254
|
+
}
|
|
252
255
|
const promises = notifyManager.batch(() =>
|
|
253
256
|
this.#queryCache
|
|
254
257
|
.findAll(filters)
|
|
255
258
|
.filter((query) => !query.isDisabled())
|
|
256
|
-
.map((query) =>
|
|
257
|
-
query.fetch(undefined,
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
259
|
+
.map((query) => {
|
|
260
|
+
let promise = query.fetch(undefined, fetchOptions)
|
|
261
|
+
if (!fetchOptions.throwOnError) {
|
|
262
|
+
promise = promise.catch(noop)
|
|
263
|
+
}
|
|
264
|
+
return query.state.fetchStatus === 'paused'
|
|
265
|
+
? Promise.resolve()
|
|
266
|
+
: promise
|
|
267
|
+
}),
|
|
262
268
|
)
|
|
263
269
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (!options?.throwOnError) {
|
|
267
|
-
promise = promise.catch(noop)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return promise
|
|
270
|
+
return Promise.all(promises).then(noop)
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
fetchQuery<
|
|
@@ -480,8 +480,8 @@ export class QueryClient {
|
|
|
480
480
|
defaultedOptions.refetchOnReconnect =
|
|
481
481
|
defaultedOptions.networkMode !== 'always'
|
|
482
482
|
}
|
|
483
|
-
if (typeof defaultedOptions.
|
|
484
|
-
defaultedOptions.
|
|
483
|
+
if (typeof defaultedOptions.throwOnError === 'undefined') {
|
|
484
|
+
defaultedOptions.throwOnError = !!defaultedOptions.suspense
|
|
485
485
|
}
|
|
486
486
|
|
|
487
487
|
return defaultedOptions as DefaultedQueryObserverOptions<
|
package/src/queryObserver.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import type { DefaultedQueryObserverOptions, DefaultError } from './types'
|
|
2
|
-
import {
|
|
3
|
-
isServer,
|
|
4
|
-
isValidTimeout,
|
|
5
|
-
noop,
|
|
6
|
-
replaceData,
|
|
7
|
-
shallowEqualObjects,
|
|
8
|
-
timeUntilStale,
|
|
9
|
-
} from './utils'
|
|
10
|
-
import { notifyManager } from './notifyManager'
|
|
11
1
|
import type {
|
|
2
|
+
DefaultedQueryObserverOptions,
|
|
3
|
+
DefaultError,
|
|
12
4
|
PlaceholderDataFunction,
|
|
13
5
|
QueryKey,
|
|
14
6
|
QueryObserverBaseResult,
|
|
@@ -17,11 +9,20 @@ import type {
|
|
|
17
9
|
QueryOptions,
|
|
18
10
|
RefetchOptions,
|
|
19
11
|
} from './types'
|
|
20
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
isServer,
|
|
14
|
+
isValidTimeout,
|
|
15
|
+
noop,
|
|
16
|
+
replaceData,
|
|
17
|
+
shallowEqualObjects,
|
|
18
|
+
timeUntilStale,
|
|
19
|
+
} from './utils'
|
|
20
|
+
import { notifyManager } from './notifyManager'
|
|
21
|
+
import type { Query, QueryState, FetchOptions } from './query'
|
|
21
22
|
import type { QueryClient } from './queryClient'
|
|
22
23
|
import { focusManager } from './focusManager'
|
|
23
24
|
import { Subscribable } from './subscribable'
|
|
24
|
-
import { canFetch
|
|
25
|
+
import { canFetch } from './retryer'
|
|
25
26
|
|
|
26
27
|
type QueryObserverListener<TData, TError> = (
|
|
27
28
|
result: QueryObserverResult<TData, TError>,
|
|
@@ -29,8 +30,6 @@ type QueryObserverListener<TData, TError> = (
|
|
|
29
30
|
|
|
30
31
|
export interface NotifyOptions {
|
|
31
32
|
listeners?: boolean
|
|
32
|
-
onError?: boolean
|
|
33
|
-
onSuccess?: boolean
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
export interface ObserverFetchOptions extends FetchOptions {
|
|
@@ -64,10 +63,12 @@ export class QueryObserver<
|
|
|
64
63
|
TQueryData,
|
|
65
64
|
TQueryKey
|
|
66
65
|
>
|
|
67
|
-
#previousQueryResult?: QueryObserverResult<TData, TError>
|
|
68
66
|
#selectError: TError | null
|
|
69
67
|
#selectFn?: (data: TQueryData) => TData
|
|
70
68
|
#selectResult?: TData
|
|
69
|
+
// This property keeps track of the last query with defined data.
|
|
70
|
+
// It will be used to pass the previous data and query to the placeholder function between renders.
|
|
71
|
+
#lastQueryWithDefinedData?: Query<TQueryFnData, TError, TQueryData, TQueryKey>
|
|
71
72
|
#staleTimeoutId?: ReturnType<typeof setTimeout>
|
|
72
73
|
#refetchIntervalId?: ReturnType<typeof setInterval>
|
|
73
74
|
#currentRefetchInterval?: number | false
|
|
@@ -97,7 +98,7 @@ export class QueryObserver<
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
protected onSubscribe(): void {
|
|
100
|
-
if (this.listeners.
|
|
101
|
+
if (this.listeners.size === 1) {
|
|
101
102
|
this.#currentQuery.addObserver(this)
|
|
102
103
|
|
|
103
104
|
if (shouldFetchOnMount(this.#currentQuery, this.options)) {
|
|
@@ -109,7 +110,7 @@ export class QueryObserver<
|
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
protected onUnsubscribe(): void {
|
|
112
|
-
if (!this.
|
|
113
|
+
if (!this.hasListeners()) {
|
|
113
114
|
this.destroy()
|
|
114
115
|
}
|
|
115
116
|
}
|
|
@@ -131,7 +132,7 @@ export class QueryObserver<
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
destroy(): void {
|
|
134
|
-
this.listeners =
|
|
135
|
+
this.listeners = new Set()
|
|
135
136
|
this.#clearStaleTimeout()
|
|
136
137
|
this.#clearRefetchInterval()
|
|
137
138
|
this.#currentQuery.removeObserver(this)
|
|
@@ -342,12 +343,14 @@ export class QueryObserver<
|
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
#computeRefetchInterval() {
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
346
|
+
return (
|
|
347
|
+
(typeof this.options.refetchInterval === 'function'
|
|
348
|
+
? this.options.refetchInterval(
|
|
349
|
+
this.#currentResult.data,
|
|
350
|
+
this.#currentQuery,
|
|
351
|
+
)
|
|
352
|
+
: this.options.refetchInterval) ?? false
|
|
353
|
+
)
|
|
351
354
|
}
|
|
352
355
|
|
|
353
356
|
#updateRefetchInterval(nextInterval: number | false): void {
|
|
@@ -414,9 +417,6 @@ export class QueryObserver<
|
|
|
414
417
|
const queryInitialState = queryChange
|
|
415
418
|
? query.state
|
|
416
419
|
: this.#currentQueryInitialState
|
|
417
|
-
const prevQueryResult = queryChange
|
|
418
|
-
? this.#currentResult
|
|
419
|
-
: this.#previousQueryResult
|
|
420
420
|
|
|
421
421
|
const { state } = query
|
|
422
422
|
let { error, errorUpdatedAt, fetchStatus, status } = state
|
|
@@ -490,7 +490,10 @@ export class QueryObserver<
|
|
|
490
490
|
typeof options.placeholderData === 'function'
|
|
491
491
|
? (
|
|
492
492
|
options.placeholderData as unknown as PlaceholderDataFunction<TQueryData>
|
|
493
|
-
)(
|
|
493
|
+
)(
|
|
494
|
+
this.#lastQueryWithDefinedData?.state.data,
|
|
495
|
+
this.#lastQueryWithDefinedData as any,
|
|
496
|
+
)
|
|
494
497
|
: options.placeholderData
|
|
495
498
|
if (options.select && typeof placeholderData !== 'undefined') {
|
|
496
499
|
try {
|
|
@@ -504,7 +507,11 @@ export class QueryObserver<
|
|
|
504
507
|
|
|
505
508
|
if (typeof placeholderData !== 'undefined') {
|
|
506
509
|
status = 'success'
|
|
507
|
-
data = replaceData(
|
|
510
|
+
data = replaceData(
|
|
511
|
+
prevResult?.data,
|
|
512
|
+
placeholderData as unknown,
|
|
513
|
+
options,
|
|
514
|
+
) as TData
|
|
508
515
|
isPlaceholderData = true
|
|
509
516
|
}
|
|
510
517
|
}
|
|
@@ -568,6 +575,9 @@ export class QueryObserver<
|
|
|
568
575
|
return
|
|
569
576
|
}
|
|
570
577
|
|
|
578
|
+
if (this.#currentResultState.data !== undefined) {
|
|
579
|
+
this.#lastQueryWithDefinedData = this.#currentQuery
|
|
580
|
+
}
|
|
571
581
|
this.#currentResult = nextResult
|
|
572
582
|
|
|
573
583
|
// Determine which callbacks to trigger
|
|
@@ -589,7 +599,7 @@ export class QueryObserver<
|
|
|
589
599
|
|
|
590
600
|
const includedProps = new Set(notifyOnChangeProps ?? this.#trackedProps)
|
|
591
601
|
|
|
592
|
-
if (this.options.
|
|
602
|
+
if (this.options.throwOnError) {
|
|
593
603
|
includedProps.add('error')
|
|
594
604
|
}
|
|
595
605
|
|
|
@@ -619,7 +629,6 @@ export class QueryObserver<
|
|
|
619
629
|
| undefined
|
|
620
630
|
this.#currentQuery = query
|
|
621
631
|
this.#currentQueryInitialState = query.state
|
|
622
|
-
this.#previousQueryResult = this.#currentResult
|
|
623
632
|
|
|
624
633
|
if (this.hasListeners()) {
|
|
625
634
|
prevQuery?.removeObserver(this)
|
|
@@ -627,16 +636,8 @@ export class QueryObserver<
|
|
|
627
636
|
}
|
|
628
637
|
}
|
|
629
638
|
|
|
630
|
-
onQueryUpdate(
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
if (action.type === 'success') {
|
|
634
|
-
notifyOptions.onSuccess = !action.manual
|
|
635
|
-
} else if (action.type === 'error' && !isCancelledError(action.error)) {
|
|
636
|
-
notifyOptions.onError = true
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
this.#updateResult(notifyOptions)
|
|
639
|
+
onQueryUpdate(): void {
|
|
640
|
+
this.#updateResult()
|
|
640
641
|
|
|
641
642
|
if (this.hasListeners()) {
|
|
642
643
|
this.#updateTimers()
|
|
@@ -645,16 +646,7 @@ export class QueryObserver<
|
|
|
645
646
|
|
|
646
647
|
#notify(notifyOptions: NotifyOptions): void {
|
|
647
648
|
notifyManager.batch(() => {
|
|
648
|
-
// First trigger the
|
|
649
|
-
if (notifyOptions.onSuccess) {
|
|
650
|
-
this.options.onSuccess?.(this.#currentResult.data!)
|
|
651
|
-
this.options.onSettled?.(this.#currentResult.data, null)
|
|
652
|
-
} else if (notifyOptions.onError) {
|
|
653
|
-
this.options.onError?.(this.#currentResult.error!)
|
|
654
|
-
this.options.onSettled?.(undefined, this.#currentResult.error)
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// Then trigger the listeners
|
|
649
|
+
// First, trigger the listeners
|
|
658
650
|
if (notifyOptions.listeners) {
|
|
659
651
|
this.listeners.forEach((listener) => {
|
|
660
652
|
listener(this.#currentResult)
|
package/src/subscribable.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
type Listener = () => void
|
|
2
2
|
|
|
3
3
|
export class Subscribable<TListener extends Function = Listener> {
|
|
4
|
-
protected listeners: TListener
|
|
4
|
+
protected listeners: Set<TListener>
|
|
5
5
|
|
|
6
6
|
constructor() {
|
|
7
|
-
this.listeners =
|
|
7
|
+
this.listeners = new Set()
|
|
8
8
|
this.subscribe = this.subscribe.bind(this)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
subscribe(listener: TListener): () => void {
|
|
12
|
-
this.listeners.
|
|
12
|
+
this.listeners.add(listener)
|
|
13
13
|
|
|
14
14
|
this.onSubscribe()
|
|
15
15
|
|
|
16
16
|
return () => {
|
|
17
|
-
this.listeners
|
|
17
|
+
this.listeners.delete(listener)
|
|
18
18
|
this.onUnsubscribe()
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
hasListeners(): boolean {
|
|
23
|
-
return this.listeners.
|
|
23
|
+
return this.listeners.size > 0
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
protected onSubscribe(): void {
|
|
@@ -113,7 +113,9 @@ describe('dehydration and rehydration', () => {
|
|
|
113
113
|
queryFn: () => fetchData('string'),
|
|
114
114
|
})
|
|
115
115
|
|
|
116
|
-
const dehydrated = dehydrate(queryClient, {
|
|
116
|
+
const dehydrated = dehydrate(queryClient, {
|
|
117
|
+
shouldDehydrateQuery: () => false,
|
|
118
|
+
})
|
|
117
119
|
|
|
118
120
|
expect(dehydrated.queries.length).toBe(0)
|
|
119
121
|
|
|
@@ -244,7 +246,7 @@ describe('dehydration and rehydration', () => {
|
|
|
244
246
|
consoleMock.mockRestore()
|
|
245
247
|
})
|
|
246
248
|
|
|
247
|
-
test('should filter queries via
|
|
249
|
+
test('should filter queries via dehydrateQuery', async () => {
|
|
248
250
|
const queryCache = new QueryCache()
|
|
249
251
|
const queryClient = createQueryClient({ queryCache })
|
|
250
252
|
await queryClient.prefetchQuery({
|
|
@@ -446,7 +448,9 @@ describe('dehydration and rehydration', () => {
|
|
|
446
448
|
).catch(() => undefined)
|
|
447
449
|
|
|
448
450
|
await sleep(1)
|
|
449
|
-
const dehydrated = dehydrate(queryClient, {
|
|
451
|
+
const dehydrated = dehydrate(queryClient, {
|
|
452
|
+
shouldDehydrateMutation: () => false,
|
|
453
|
+
})
|
|
450
454
|
|
|
451
455
|
expect(dehydrated.mutations.length).toBe(0)
|
|
452
456
|
|
|
@@ -82,6 +82,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
82
82
|
queryKey: key,
|
|
83
83
|
pageParam: 1,
|
|
84
84
|
meta: undefined,
|
|
85
|
+
direction: 'forward',
|
|
85
86
|
signal: abortSignal,
|
|
86
87
|
})
|
|
87
88
|
|
|
@@ -93,6 +94,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
93
94
|
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
94
95
|
queryKey: key,
|
|
95
96
|
pageParam: 2,
|
|
97
|
+
direction: 'forward',
|
|
96
98
|
meta: undefined,
|
|
97
99
|
signal: abortSignal,
|
|
98
100
|
})
|
|
@@ -110,6 +112,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
110
112
|
expect(queryFnSpy).toHaveBeenNthCalledWith(1, {
|
|
111
113
|
queryKey: key,
|
|
112
114
|
pageParam: 0,
|
|
115
|
+
direction: 'backward',
|
|
113
116
|
meta: undefined,
|
|
114
117
|
signal: abortSignal,
|
|
115
118
|
})
|
|
@@ -129,6 +132,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
129
132
|
queryKey: key,
|
|
130
133
|
pageParam: -1,
|
|
131
134
|
meta: undefined,
|
|
135
|
+
direction: 'backward',
|
|
132
136
|
signal: abortSignal,
|
|
133
137
|
})
|
|
134
138
|
|
|
@@ -146,6 +150,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
146
150
|
queryKey: key,
|
|
147
151
|
pageParam: 1,
|
|
148
152
|
meta: undefined,
|
|
153
|
+
direction: 'forward',
|
|
149
154
|
signal: abortSignal,
|
|
150
155
|
})
|
|
151
156
|
|
|
@@ -166,6 +171,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
166
171
|
queryKey: key,
|
|
167
172
|
pageParam: 0,
|
|
168
173
|
meta: undefined,
|
|
174
|
+
direction: 'forward',
|
|
169
175
|
signal: abortSignal,
|
|
170
176
|
})
|
|
171
177
|
|
|
@@ -173,6 +179,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
173
179
|
queryKey: key,
|
|
174
180
|
pageParam: 1,
|
|
175
181
|
meta: undefined,
|
|
182
|
+
direction: 'forward',
|
|
176
183
|
signal: abortSignal,
|
|
177
184
|
})
|
|
178
185
|
|
|
@@ -224,6 +231,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
224
231
|
queryKey: key,
|
|
225
232
|
pageParam: 1,
|
|
226
233
|
meta: undefined,
|
|
234
|
+
direction: 'forward',
|
|
227
235
|
signal: abortSignal,
|
|
228
236
|
})
|
|
229
237
|
|
|
@@ -279,6 +287,7 @@ describe('InfiniteQueryBehavior', () => {
|
|
|
279
287
|
queryKey: key,
|
|
280
288
|
pageParam: 2,
|
|
281
289
|
meta: undefined,
|
|
290
|
+
direction: 'forward',
|
|
282
291
|
signal: abortSignal,
|
|
283
292
|
})
|
|
284
293
|
|
package/src/tests/query.test.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { sleep, queryKey, createQueryClient } from './utils'
|
|
2
|
-
import { QueryClient } from '..'
|
|
3
|
-
import { QueryCache, QueryObserver } from '..'
|
|
2
|
+
import { QueryClient, QueryCache, QueryObserver } from '..'
|
|
4
3
|
import { waitFor } from '@testing-library/react'
|
|
5
4
|
import { vi } from 'vitest'
|
|
6
5
|
|
|
@@ -329,23 +328,6 @@ describe('queryCache', () => {
|
|
|
329
328
|
})
|
|
330
329
|
})
|
|
331
330
|
|
|
332
|
-
describe('QueryCacheConfig.createStore', () => {
|
|
333
|
-
test('should call createStore', async () => {
|
|
334
|
-
const createStore = vi.fn().mockImplementation(() => new Map())
|
|
335
|
-
new QueryCache({ createStore })
|
|
336
|
-
expect(createStore).toHaveBeenCalledWith()
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
test('should use created store', async () => {
|
|
340
|
-
const store = new Map()
|
|
341
|
-
const spy = vi.spyOn(store, 'get')
|
|
342
|
-
|
|
343
|
-
new QueryCache({ createStore: () => store }).get('key')
|
|
344
|
-
|
|
345
|
-
expect(spy).toHaveBeenCalledTimes(1)
|
|
346
|
-
})
|
|
347
|
-
})
|
|
348
|
-
|
|
349
331
|
describe('QueryCache.add', () => {
|
|
350
332
|
test('should not try to add a query already added to the cache', async () => {
|
|
351
333
|
const key = queryKey()
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { waitFor } from '@testing-library/react'
|
|
2
2
|
import '@testing-library/jest-dom'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
sleep,
|
|
6
|
+
queryKey,
|
|
7
|
+
createQueryClient,
|
|
8
|
+
mockNavigatorOnLine,
|
|
9
|
+
} from './utils'
|
|
5
10
|
import type {
|
|
6
11
|
QueryCache,
|
|
7
12
|
QueryClient,
|
|
8
13
|
QueryFunction,
|
|
9
14
|
QueryObserverOptions,
|
|
10
15
|
} from '..'
|
|
11
|
-
import {
|
|
12
|
-
|
|
16
|
+
import {
|
|
17
|
+
MutationObserver,
|
|
18
|
+
QueryObserver,
|
|
19
|
+
focusManager,
|
|
20
|
+
onlineManager,
|
|
21
|
+
} from '..'
|
|
13
22
|
import { noop } from '../utils'
|
|
14
23
|
import { vi } from 'vitest'
|
|
15
24
|
|
|
@@ -1020,6 +1029,33 @@ describe('queryClient', () => {
|
|
|
1020
1029
|
}
|
|
1021
1030
|
expect(error).toEqual('error')
|
|
1022
1031
|
})
|
|
1032
|
+
|
|
1033
|
+
test('should resolve Promise immediately if query is paused', async () => {
|
|
1034
|
+
const key1 = queryKey()
|
|
1035
|
+
const queryFn1 = vi.fn<unknown[], string>().mockReturnValue('data1')
|
|
1036
|
+
await queryClient.fetchQuery({ queryKey: key1, queryFn: queryFn1 })
|
|
1037
|
+
const onlineMock = mockNavigatorOnLine(false)
|
|
1038
|
+
|
|
1039
|
+
await queryClient.refetchQueries({ queryKey: key1 })
|
|
1040
|
+
|
|
1041
|
+
// if we reach this point, the test succeeds because the Promise was resolved immediately
|
|
1042
|
+
expect(queryFn1).toHaveBeenCalledTimes(1)
|
|
1043
|
+
onlineMock.mockRestore()
|
|
1044
|
+
})
|
|
1045
|
+
|
|
1046
|
+
test('should refetch if query we are offline but query networkMode is always', async () => {
|
|
1047
|
+
const key1 = queryKey()
|
|
1048
|
+
queryClient.setQueryDefaults(key1, { networkMode: 'always' })
|
|
1049
|
+
const queryFn1 = vi.fn<unknown[], string>().mockReturnValue('data1')
|
|
1050
|
+
await queryClient.fetchQuery({ queryKey: key1, queryFn: queryFn1 })
|
|
1051
|
+
const onlineMock = mockNavigatorOnLine(false)
|
|
1052
|
+
|
|
1053
|
+
await queryClient.refetchQueries({ queryKey: key1 })
|
|
1054
|
+
|
|
1055
|
+
// initial fetch + refetch (even though we are offline)
|
|
1056
|
+
expect(queryFn1).toHaveBeenCalledTimes(2)
|
|
1057
|
+
onlineMock.mockRestore()
|
|
1058
|
+
})
|
|
1023
1059
|
})
|
|
1024
1060
|
|
|
1025
1061
|
describe('invalidateQueries', () => {
|
|
@@ -691,6 +691,127 @@ describe('queryObserver', () => {
|
|
|
691
691
|
expect(observer.getCurrentResult().isPlaceholderData).toBe(false)
|
|
692
692
|
})
|
|
693
693
|
|
|
694
|
+
test('should pass the correct previous queryKey (from prevQuery) to placeholderData function params with select', async () => {
|
|
695
|
+
const results: QueryObserverResult[] = []
|
|
696
|
+
const keys: Array<readonly unknown[] | null> = []
|
|
697
|
+
|
|
698
|
+
const key1 = queryKey()
|
|
699
|
+
const key2 = queryKey()
|
|
700
|
+
|
|
701
|
+
const data1 = { value: 'data1' }
|
|
702
|
+
const data2 = { value: 'data2' }
|
|
703
|
+
|
|
704
|
+
const observer = new QueryObserver(queryClient, {
|
|
705
|
+
queryKey: key1,
|
|
706
|
+
queryFn: () => data1,
|
|
707
|
+
placeholderData: (prev, prevQuery) => {
|
|
708
|
+
keys.push(prevQuery?.queryKey || null)
|
|
709
|
+
return prev
|
|
710
|
+
},
|
|
711
|
+
select: (data) => data.value,
|
|
712
|
+
})
|
|
713
|
+
|
|
714
|
+
const unsubscribe = observer.subscribe((result) => {
|
|
715
|
+
results.push(result)
|
|
716
|
+
})
|
|
717
|
+
|
|
718
|
+
await sleep(1)
|
|
719
|
+
|
|
720
|
+
observer.setOptions({
|
|
721
|
+
queryKey: key2,
|
|
722
|
+
queryFn: () => data2,
|
|
723
|
+
placeholderData: (prev, prevQuery) => {
|
|
724
|
+
keys.push(prevQuery?.queryKey || null)
|
|
725
|
+
return prev
|
|
726
|
+
},
|
|
727
|
+
select: (data) => data.value,
|
|
728
|
+
})
|
|
729
|
+
|
|
730
|
+
await sleep(1)
|
|
731
|
+
unsubscribe()
|
|
732
|
+
expect(results.length).toBe(4)
|
|
733
|
+
expect(keys.length).toBe(3)
|
|
734
|
+
expect(keys[0]).toBe(null) // First Query - status: 'pending', fetchStatus: 'idle'
|
|
735
|
+
expect(keys[1]).toBe(null) // First Query - status: 'pending', fetchStatus: 'fetching'
|
|
736
|
+
expect(keys[2]).toBe(key1) // Second Query - status: 'pending', fetchStatus: 'fetching'
|
|
737
|
+
|
|
738
|
+
expect(results[0]).toMatchObject({
|
|
739
|
+
data: undefined,
|
|
740
|
+
status: 'pending',
|
|
741
|
+
fetchStatus: 'fetching',
|
|
742
|
+
}) // Initial fetch
|
|
743
|
+
expect(results[1]).toMatchObject({
|
|
744
|
+
data: 'data1',
|
|
745
|
+
status: 'success',
|
|
746
|
+
fetchStatus: 'idle',
|
|
747
|
+
}) // Successful fetch
|
|
748
|
+
expect(results[2]).toMatchObject({
|
|
749
|
+
data: 'data1',
|
|
750
|
+
status: 'success',
|
|
751
|
+
fetchStatus: 'fetching',
|
|
752
|
+
}) // Fetch for new key, but using previous data as placeholder
|
|
753
|
+
expect(results[3]).toMatchObject({
|
|
754
|
+
data: 'data2',
|
|
755
|
+
status: 'success',
|
|
756
|
+
fetchStatus: 'idle',
|
|
757
|
+
}) // Successful fetch for new key
|
|
758
|
+
})
|
|
759
|
+
|
|
760
|
+
test('should pass the correct previous data to placeholderData function params when select function is used in conjunction', async () => {
|
|
761
|
+
const results: QueryObserverResult[] = []
|
|
762
|
+
|
|
763
|
+
const key1 = queryKey()
|
|
764
|
+
const key2 = queryKey()
|
|
765
|
+
|
|
766
|
+
const data1 = { value: 'data1' }
|
|
767
|
+
const data2 = { value: 'data2' }
|
|
768
|
+
|
|
769
|
+
const observer = new QueryObserver(queryClient, {
|
|
770
|
+
queryKey: key1,
|
|
771
|
+
queryFn: () => data1,
|
|
772
|
+
placeholderData: (prev) => prev,
|
|
773
|
+
select: (data) => data.value,
|
|
774
|
+
})
|
|
775
|
+
|
|
776
|
+
const unsubscribe = observer.subscribe((result) => {
|
|
777
|
+
results.push(result)
|
|
778
|
+
})
|
|
779
|
+
|
|
780
|
+
await sleep(1)
|
|
781
|
+
|
|
782
|
+
observer.setOptions({
|
|
783
|
+
queryKey: key2,
|
|
784
|
+
queryFn: () => data2,
|
|
785
|
+
placeholderData: (prev) => prev,
|
|
786
|
+
select: (data) => data.value,
|
|
787
|
+
})
|
|
788
|
+
|
|
789
|
+
await sleep(1)
|
|
790
|
+
unsubscribe()
|
|
791
|
+
|
|
792
|
+
expect(results.length).toBe(4)
|
|
793
|
+
expect(results[0]).toMatchObject({
|
|
794
|
+
data: undefined,
|
|
795
|
+
status: 'pending',
|
|
796
|
+
fetchStatus: 'fetching',
|
|
797
|
+
}) // Initial fetch
|
|
798
|
+
expect(results[1]).toMatchObject({
|
|
799
|
+
data: 'data1',
|
|
800
|
+
status: 'success',
|
|
801
|
+
fetchStatus: 'idle',
|
|
802
|
+
}) // Successful fetch
|
|
803
|
+
expect(results[2]).toMatchObject({
|
|
804
|
+
data: 'data1',
|
|
805
|
+
status: 'success',
|
|
806
|
+
fetchStatus: 'fetching',
|
|
807
|
+
}) // Fetch for new key, but using previous data as placeholder
|
|
808
|
+
expect(results[3]).toMatchObject({
|
|
809
|
+
data: 'data2',
|
|
810
|
+
status: 'success',
|
|
811
|
+
fetchStatus: 'idle',
|
|
812
|
+
}) // Successful fetch for new key
|
|
813
|
+
})
|
|
814
|
+
|
|
694
815
|
test('setOptions should notify cache listeners', async () => {
|
|
695
816
|
const key = queryKey()
|
|
696
817
|
|