@tanstack/query-core 5.0.0-alpha.5 → 5.0.0-alpha.51

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.
Files changed (221) hide show
  1. package/build/lib/{focusManager.esm.js → focusManager.cjs} +9 -6
  2. package/build/lib/{focusManager.mjs.map → focusManager.cjs.map} +1 -1
  3. package/build/lib/focusManager.d.ts +2 -1
  4. package/build/lib/focusManager.d.ts.map +1 -0
  5. package/build/lib/focusManager.js +5 -8
  6. package/build/lib/focusManager.js.map +1 -1
  7. package/build/lib/{hydration.mjs → hydration.cjs} +11 -20
  8. package/build/lib/hydration.cjs.map +1 -0
  9. package/build/lib/hydration.d.ts +3 -6
  10. package/build/lib/hydration.d.ts.map +1 -0
  11. package/build/lib/hydration.js +5 -24
  12. package/build/lib/hydration.js.map +1 -1
  13. package/build/lib/index.cjs +40 -0
  14. package/build/lib/index.cjs.map +1 -0
  15. package/build/lib/index.d.ts +5 -3
  16. package/build/lib/index.d.ts.map +1 -0
  17. package/build/lib/index.js +13 -39
  18. package/build/lib/index.js.map +1 -1
  19. package/build/lib/{infiniteQueryBehavior.esm.js → infiniteQueryBehavior.cjs} +9 -4
  20. package/build/lib/infiniteQueryBehavior.cjs.map +1 -0
  21. package/build/lib/infiniteQueryBehavior.d.ts +1 -0
  22. package/build/lib/infiniteQueryBehavior.d.ts.map +1 -0
  23. package/build/lib/infiniteQueryBehavior.js +4 -7
  24. package/build/lib/infiniteQueryBehavior.js.map +1 -1
  25. package/build/lib/{infiniteQueryObserver.esm.js → infiniteQueryObserver.cjs} +11 -9
  26. package/build/lib/{infiniteQueryObserver.mjs.map → infiniteQueryObserver.cjs.map} +1 -1
  27. package/build/lib/infiniteQueryObserver.d.ts +2 -1
  28. package/build/lib/infiniteQueryObserver.d.ts.map +1 -0
  29. package/build/lib/infiniteQueryObserver.js +8 -10
  30. package/build/lib/infiniteQueryObserver.js.map +1 -1
  31. package/build/lib/{mutation.esm.js → mutation.cjs} +12 -9
  32. package/build/lib/{mutation.mjs.map → mutation.cjs.map} +1 -1
  33. package/build/lib/mutation.d.ts +2 -1
  34. package/build/lib/mutation.d.ts.map +1 -0
  35. package/build/lib/mutation.js +8 -11
  36. package/build/lib/mutation.js.map +1 -1
  37. package/build/lib/{mutationCache.esm.js → mutationCache.cjs} +21 -18
  38. package/build/lib/mutationCache.cjs.map +1 -0
  39. package/build/lib/mutationCache.d.ts +3 -2
  40. package/build/lib/mutationCache.d.ts.map +1 -0
  41. package/build/lib/mutationCache.js +18 -19
  42. package/build/lib/mutationCache.js.map +1 -1
  43. package/build/lib/{mutationObserver.esm.js → mutationObserver.cjs} +13 -11
  44. package/build/lib/mutationObserver.cjs.map +1 -0
  45. package/build/lib/mutationObserver.d.ts +2 -1
  46. package/build/lib/mutationObserver.d.ts.map +1 -0
  47. package/build/lib/mutationObserver.js +10 -12
  48. package/build/lib/mutationObserver.js.map +1 -1
  49. package/build/lib/{notifyManager.esm.js → notifyManager.cjs} +8 -5
  50. package/build/lib/{notifyManager.mjs.map → notifyManager.cjs.map} +1 -1
  51. package/build/lib/notifyManager.d.ts +4 -3
  52. package/build/lib/notifyManager.d.ts.map +1 -0
  53. package/build/lib/notifyManager.js +4 -7
  54. package/build/lib/notifyManager.js.map +1 -1
  55. package/build/lib/{onlineManager.esm.js → onlineManager.cjs} +9 -6
  56. package/build/lib/{onlineManager.mjs.map → onlineManager.cjs.map} +1 -1
  57. package/build/lib/onlineManager.d.ts +2 -1
  58. package/build/lib/onlineManager.d.ts.map +1 -0
  59. package/build/lib/onlineManager.js +5 -8
  60. package/build/lib/onlineManager.js.map +1 -1
  61. package/build/lib/{queriesObserver.esm.js → queriesObserver.cjs} +50 -25
  62. package/build/lib/queriesObserver.cjs.map +1 -0
  63. package/build/lib/queriesObserver.d.ts +14 -6
  64. package/build/lib/queriesObserver.d.ts.map +1 -0
  65. package/build/lib/queriesObserver.js +47 -26
  66. package/build/lib/queriesObserver.js.map +1 -1
  67. package/build/lib/{query.mjs → query.cjs} +20 -18
  68. package/build/lib/query.cjs.map +1 -0
  69. package/build/lib/query.d.ts +6 -4
  70. package/build/lib/query.d.ts.map +1 -0
  71. package/build/lib/query.js +17 -19
  72. package/build/lib/query.js.map +1 -1
  73. package/build/lib/{queryCache.mjs → queryCache.cjs} +28 -23
  74. package/build/lib/queryCache.cjs.map +1 -0
  75. package/build/lib/queryCache.d.ts +3 -3
  76. package/build/lib/queryCache.d.ts.map +1 -0
  77. package/build/lib/queryCache.js +24 -23
  78. package/build/lib/queryCache.js.map +1 -1
  79. package/build/lib/{queryClient.esm.js → queryClient.cjs} +50 -42
  80. package/build/lib/queryClient.cjs.map +1 -0
  81. package/build/lib/queryClient.d.ts +2 -2
  82. package/build/lib/queryClient.d.ts.map +1 -0
  83. package/build/lib/queryClient.js +46 -42
  84. package/build/lib/queryClient.js.map +1 -1
  85. package/build/lib/{queryObserver.mjs → queryObserver.cjs} +36 -46
  86. package/build/lib/queryObserver.cjs.map +1 -0
  87. package/build/lib/queryObserver.d.ts +5 -7
  88. package/build/lib/queryObserver.d.ts.map +1 -0
  89. package/build/lib/queryObserver.js +33 -47
  90. package/build/lib/queryObserver.js.map +1 -1
  91. package/build/lib/{removable.esm.js → removable.cjs} +7 -5
  92. package/build/lib/{removable.mjs.map → removable.cjs.map} +1 -1
  93. package/build/lib/removable.d.ts +1 -0
  94. package/build/lib/removable.d.ts.map +1 -0
  95. package/build/lib/removable.js +4 -6
  96. package/build/lib/removable.js.map +1 -1
  97. package/build/lib/{retryer.esm.js → retryer.cjs} +15 -8
  98. package/build/lib/{retryer.mjs.map → retryer.cjs.map} +1 -1
  99. package/build/lib/retryer.d.ts +5 -4
  100. package/build/lib/retryer.d.ts.map +1 -0
  101. package/build/lib/retryer.js +8 -11
  102. package/build/lib/retryer.js.map +1 -1
  103. package/build/lib/{subscribable.esm.js → subscribable.cjs} +8 -6
  104. package/build/lib/subscribable.cjs.map +1 -0
  105. package/build/lib/subscribable.d.ts +3 -2
  106. package/build/lib/subscribable.d.ts.map +1 -0
  107. package/build/lib/subscribable.js +5 -7
  108. package/build/lib/subscribable.js.map +1 -1
  109. package/build/lib/tests/focusManager.test.d.ts +1 -0
  110. package/build/lib/tests/focusManager.test.d.ts.map +1 -0
  111. package/build/lib/tests/hydration.test.d.ts +1 -0
  112. package/build/lib/tests/hydration.test.d.ts.map +1 -0
  113. package/build/lib/tests/infiniteQueryBehavior.test.d.ts +1 -0
  114. package/build/lib/tests/infiniteQueryBehavior.test.d.ts.map +1 -0
  115. package/build/lib/tests/infiniteQueryObserver.test.d.ts +1 -0
  116. package/build/lib/tests/infiniteQueryObserver.test.d.ts.map +1 -0
  117. package/build/lib/tests/mutationCache.test.d.ts +1 -0
  118. package/build/lib/tests/mutationCache.test.d.ts.map +1 -0
  119. package/build/lib/tests/mutationObserver.test.d.ts +1 -0
  120. package/build/lib/tests/mutationObserver.test.d.ts.map +1 -0
  121. package/build/lib/tests/mutations.test.d.ts +1 -0
  122. package/build/lib/tests/mutations.test.d.ts.map +1 -0
  123. package/build/lib/tests/notifyManager.test.d.ts +1 -0
  124. package/build/lib/tests/notifyManager.test.d.ts.map +1 -0
  125. package/build/lib/tests/onlineManager.test.d.ts +1 -0
  126. package/build/lib/tests/onlineManager.test.d.ts.map +1 -0
  127. package/build/lib/tests/queriesObserver.test.d.ts +1 -0
  128. package/build/lib/tests/queriesObserver.test.d.ts.map +1 -0
  129. package/build/lib/tests/query.test.d.ts +1 -0
  130. package/build/lib/tests/query.test.d.ts.map +1 -0
  131. package/build/lib/tests/queryCache.test.d.ts +1 -0
  132. package/build/lib/tests/queryCache.test.d.ts.map +1 -0
  133. package/build/lib/tests/queryClient.test.d.ts +1 -0
  134. package/build/lib/tests/queryClient.test.d.ts.map +1 -0
  135. package/build/lib/tests/queryObserver.test.d.ts +1 -0
  136. package/build/lib/tests/queryObserver.test.d.ts.map +1 -0
  137. package/build/lib/tests/utils.d.ts +3 -2
  138. package/build/lib/tests/utils.d.ts.map +1 -0
  139. package/build/lib/tests/utils.test.d.ts +1 -0
  140. package/build/lib/tests/utils.test.d.ts.map +1 -0
  141. package/build/lib/types.d.ts +35 -45
  142. package/build/lib/types.d.ts.map +1 -0
  143. package/build/lib/{utils.esm.js → utils.cjs} +23 -2
  144. package/build/lib/{utils.mjs.map → utils.cjs.map} +1 -1
  145. package/build/lib/utils.d.ts +4 -3
  146. package/build/lib/utils.d.ts.map +1 -0
  147. package/build/lib/utils.js +1 -22
  148. package/build/lib/utils.js.map +1 -1
  149. package/package.json +12 -9
  150. package/src/hydration.ts +18 -37
  151. package/src/index.ts +3 -4
  152. package/src/infiniteQueryBehavior.ts +1 -0
  153. package/src/mutationCache.ts +4 -4
  154. package/src/mutationObserver.ts +1 -1
  155. package/src/queriesObserver.ts +74 -24
  156. package/src/query.ts +7 -5
  157. package/src/queryCache.ts +5 -8
  158. package/src/queryClient.ts +20 -20
  159. package/src/queryObserver.ts +43 -51
  160. package/src/subscribable.ts +5 -5
  161. package/src/tests/hydration.test.tsx +7 -3
  162. package/src/tests/infiniteQueryBehavior.test.tsx +9 -0
  163. package/src/tests/query.test.tsx +1 -1
  164. package/src/tests/queryCache.test.tsx +1 -19
  165. package/src/tests/queryClient.test.tsx +39 -3
  166. package/src/tests/queryObserver.test.tsx +121 -0
  167. package/src/types.ts +15 -20
  168. package/build/lib/focusManager.esm.js.map +0 -1
  169. package/build/lib/focusManager.mjs +0 -71
  170. package/build/lib/hydration.esm.js +0 -98
  171. package/build/lib/hydration.esm.js.map +0 -1
  172. package/build/lib/hydration.mjs.map +0 -1
  173. package/build/lib/index.esm.js +0 -14
  174. package/build/lib/index.esm.js.map +0 -1
  175. package/build/lib/index.mjs +0 -14
  176. package/build/lib/index.mjs.map +0 -1
  177. package/build/lib/infiniteQueryBehavior.esm.js.map +0 -1
  178. package/build/lib/infiniteQueryBehavior.mjs +0 -125
  179. package/build/lib/infiniteQueryBehavior.mjs.map +0 -1
  180. package/build/lib/infiniteQueryObserver.esm.js.map +0 -1
  181. package/build/lib/infiniteQueryObserver.mjs +0 -75
  182. package/build/lib/mutation.esm.js.map +0 -1
  183. package/build/lib/mutation.mjs +0 -234
  184. package/build/lib/mutationCache.esm.js.map +0 -1
  185. package/build/lib/mutationCache.mjs +0 -82
  186. package/build/lib/mutationCache.mjs.map +0 -1
  187. package/build/lib/mutationObserver.esm.js.map +0 -1
  188. package/build/lib/mutationObserver.mjs +0 -96
  189. package/build/lib/mutationObserver.mjs.map +0 -1
  190. package/build/lib/notifyManager.esm.js.map +0 -1
  191. package/build/lib/notifyManager.mjs +0 -89
  192. package/build/lib/onlineManager.esm.js.map +0 -1
  193. package/build/lib/onlineManager.mjs +0 -73
  194. package/build/lib/queriesObserver.esm.js.map +0 -1
  195. package/build/lib/queriesObserver.mjs +0 -136
  196. package/build/lib/queriesObserver.mjs.map +0 -1
  197. package/build/lib/query.esm.js +0 -420
  198. package/build/lib/query.esm.js.map +0 -1
  199. package/build/lib/query.mjs.map +0 -1
  200. package/build/lib/queryCache.esm.js +0 -101
  201. package/build/lib/queryCache.esm.js.map +0 -1
  202. package/build/lib/queryCache.mjs.map +0 -1
  203. package/build/lib/queryClient.esm.js.map +0 -1
  204. package/build/lib/queryClient.mjs +0 -277
  205. package/build/lib/queryClient.mjs.map +0 -1
  206. package/build/lib/queryObserver.esm.js +0 -440
  207. package/build/lib/queryObserver.esm.js.map +0 -1
  208. package/build/lib/queryObserver.mjs.map +0 -1
  209. package/build/lib/removable.esm.js.map +0 -1
  210. package/build/lib/removable.mjs +0 -29
  211. package/build/lib/retryer.esm.js.map +0 -1
  212. package/build/lib/retryer.mjs +0 -150
  213. package/build/lib/subscribable.esm.js.map +0 -1
  214. package/build/lib/subscribable.mjs +0 -26
  215. package/build/lib/subscribable.mjs.map +0 -1
  216. package/build/lib/utils.esm.js.map +0 -1
  217. package/build/lib/utils.mjs +0 -227
  218. package/build/umd/index.development.js +0 -2682
  219. package/build/umd/index.development.js.map +0 -1
  220. package/build/umd/index.production.js +0 -2
  221. package/build/umd/index.production.js.map +0 -1
@@ -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 type { Query, QueryState, Action, FetchOptions } from './query'
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, isCancelledError } from './retryer'
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.length === 1) {
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.listeners.length) {
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 typeof this.options.refetchInterval === 'function'
346
- ? this.options.refetchInterval(
347
- this.#currentResult.data,
348
- this.#currentQuery,
349
- )
350
- : this.options.refetchInterval ?? false
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
- )(prevQueryResult?.data as TQueryData | undefined)
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(prevResult?.data, placeholderData, options) as TData
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.throwErrors) {
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(action: Action<TData, TError>): void {
631
- const notifyOptions: NotifyOptions = {}
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 configuration callbacks
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)
@@ -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.push(listener)
12
+ this.listeners.add(listener)
13
13
 
14
14
  this.onSubscribe()
15
15
 
16
16
  return () => {
17
- this.listeners = this.listeners.filter((x) => x !== listener)
17
+ this.listeners.delete(listener)
18
18
  this.onUnsubscribe()
19
19
  }
20
20
  }
21
21
 
22
22
  hasListeners(): boolean {
23
- return this.listeners.length > 0
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, { dehydrateQueries: false })
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 shouldDehydrateQuery', async () => {
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, { dehydrateMutations: false })
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
 
@@ -788,7 +788,7 @@ describe('query', () => {
788
788
 
789
789
  await sleep(10)
790
790
 
791
- const error = new Error('undefined')
791
+ const error = new Error(`${JSON.stringify(key)} data is undefined`)
792
792
 
793
793
  expect(observerResult).toMatchObject({
794
794
  isError: true,
@@ -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 { sleep, queryKey, createQueryClient } from './utils'
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 { MutationObserver, QueryObserver } from '..'
12
- import { focusManager, onlineManager } from '..'
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
 
package/src/types.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /* istanbul ignore file */
2
2
 
3
3
  import type { MutationState } from './mutation'
4
- import type { QueryBehavior, Query } from './query'
4
+ import type { FetchDirection, QueryBehavior, Query } from './query'
5
5
  import type { RetryValue, RetryDelayValue } from './retryer'
6
6
  import type { QueryFilters, QueryTypeFilter } from './utils'
7
7
  import type { QueryCache } from './queryCache'
@@ -40,6 +40,7 @@ export type QueryFunctionContext<
40
40
  queryKey: TQueryKey
41
41
  signal: AbortSignal
42
42
  pageParam: TPageParam
43
+ direction: FetchDirection
43
44
  meta: QueryMeta | undefined
44
45
  }
45
46
 
@@ -47,8 +48,14 @@ export type InitialDataFunction<T> = () => T | undefined
47
48
 
48
49
  type NonFunctionGuard<T> = T extends Function ? never : T
49
50
 
50
- export type PlaceholderDataFunction<TQueryData> = (
51
+ export type PlaceholderDataFunction<
52
+ TQueryFnData = unknown,
53
+ TError = DefaultError,
54
+ TQueryData = TQueryFnData,
55
+ TQueryKey extends QueryKey = QueryKey,
56
+ > = (
51
57
  previousData: TQueryData | undefined,
58
+ previousQuery: Query<TQueryFnData, TError, TQueryData, TQueryKey> | undefined,
52
59
  ) => TQueryData | undefined
53
60
 
54
61
  export type QueriesPlaceholderDataFunction<TQueryData> = () =>
@@ -152,7 +159,7 @@ export interface InfiniteQueryPageParamsOptions<
152
159
  getNextPageParam: GetNextPageParamFunction<TPageParam, TQueryFnData>
153
160
  }
154
161
 
155
- export type ThrowErrors<
162
+ export type ThrowOnError<
156
163
  TQueryFnData,
157
164
  TError,
158
165
  TQueryData,
@@ -200,7 +207,7 @@ export interface QueryObserverOptions<
200
207
  | ((
201
208
  data: TData | undefined,
202
209
  query: Query<TQueryFnData, TError, TQueryData, TQueryKey>,
203
- ) => number | false)
210
+ ) => number | false | undefined)
204
211
  /**
205
212
  * If set to `true`, the query will continue to refetch while their tab/window is in the background.
206
213
  * Defaults to `false`.
@@ -257,18 +264,6 @@ export interface QueryObserverOptions<
257
264
  * By default, access to properties will be tracked, and the component will only re-render when one of the tracked properties change.
258
265
  */
259
266
  notifyOnChangeProps?: Array<keyof InfiniteQueryObserverResult> | 'all'
260
- /**
261
- * This callback will fire any time the query successfully fetches new data.
262
- */
263
- onSuccess?: (data: TData) => void
264
- /**
265
- * This callback will fire if the query encounters an error and will be passed the error.
266
- */
267
- onError?: (err: TError) => void
268
- /**
269
- * This callback will fire any time the query is either successfully fetched or errors and be passed either the data or error.
270
- */
271
- onSettled?: (data: TData | undefined, error: TError | null) => void
272
267
  /**
273
268
  * Whether errors should be thrown instead of setting the `error` property.
274
269
  * If set to `true` or `suspense` is `true`, all errors will be thrown to the error boundary.
@@ -276,7 +271,7 @@ export interface QueryObserverOptions<
276
271
  * If set to a function, it will be passed the error and the query, and it should return a boolean indicating whether to show the error in an error boundary (`true`) or return the error as state (`false`).
277
272
  * Defaults to `false`.
278
273
  */
279
- throwErrors?: ThrowErrors<TQueryFnData, TError, TQueryData, TQueryKey>
274
+ throwOnError?: ThrowOnError<TQueryFnData, TError, TQueryData, TQueryKey>
280
275
  /**
281
276
  * This option can be used to transform or select a part of the data returned by the query function.
282
277
  */
@@ -307,7 +302,7 @@ export type DefaultedQueryObserverOptions<
307
302
  TQueryKey extends QueryKey = QueryKey,
308
303
  > = WithRequired<
309
304
  QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,
310
- 'throwErrors' | 'refetchOnReconnect'
305
+ 'throwOnError' | 'refetchOnReconnect'
311
306
  >
312
307
 
313
308
  export interface InfiniteQueryObserverOptions<
@@ -343,7 +338,7 @@ export type DefaultedInfiniteQueryObserverOptions<
343
338
  TQueryKey,
344
339
  TPageParam
345
340
  >,
346
- 'throwErrors' | 'refetchOnReconnect'
341
+ 'throwOnError' | 'refetchOnReconnect'
347
342
  >
348
343
 
349
344
  export interface FetchQueryOptions<
@@ -646,7 +641,7 @@ export interface MutationObserverOptions<
646
641
  TVariables = void,
647
642
  TContext = unknown,
648
643
  > extends MutationOptions<TData, TError, TVariables, TContext> {
649
- throwErrors?: boolean | ((error: TError) => boolean)
644
+ throwOnError?: boolean | ((error: TError) => boolean)
650
645
  }
651
646
 
652
647
  export interface MutateOptions<
@@ -1 +0,0 @@
1
- {"version":3,"file":"focusManager.esm.js","sources":["../../src/focusManager.ts"],"sourcesContent":["import { Subscribable } from './subscribable'\nimport { isServer } from './utils'\n\ntype SetupFn = (\n setFocused: (focused?: boolean) => void,\n) => (() => void) | undefined\n\nexport class FocusManager extends Subscribable {\n #focused?: boolean\n #cleanup?: () => void\n\n #setup: SetupFn\n\n constructor() {\n super()\n this.#setup = (onFocus) => {\n // addEventListener does not exist in React Native, but window does\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!isServer && window.addEventListener) {\n const listener = () => onFocus()\n // Listen to visibilitychange\n window.addEventListener('visibilitychange', listener, false)\n\n return () => {\n // Be sure to unsubscribe if a new handler is set\n window.removeEventListener('visibilitychange', listener)\n }\n }\n return\n }\n }\n\n protected onSubscribe(): void {\n if (!this.#cleanup) {\n this.setEventListener(this.#setup)\n }\n }\n\n protected onUnsubscribe() {\n if (!this.hasListeners()) {\n this.#cleanup?.()\n this.#cleanup = undefined\n }\n }\n\n setEventListener(setup: SetupFn): void {\n this.#setup = setup\n this.#cleanup?.()\n this.#cleanup = setup((focused) => {\n if (typeof focused === 'boolean') {\n this.setFocused(focused)\n } else {\n this.onFocus()\n }\n })\n }\n\n setFocused(focused?: boolean): void {\n this.#focused = focused\n\n if (focused) {\n this.onFocus()\n }\n }\n\n onFocus(): void {\n this.listeners.forEach((listener) => {\n listener()\n })\n }\n\n isFocused(): boolean {\n if (typeof this.#focused === 'boolean') {\n return this.#focused\n }\n\n // document global can be unavailable in react native\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return globalThis.document?.visibilityState !== 'hidden'\n }\n}\n\nexport const focusManager = new FocusManager()\n"],"names":["FocusManager","Subscribable","constructor","onFocus","isServer","window","addEventListener","listener","removeEventListener","onSubscribe","setEventListener","onUnsubscribe","hasListeners","undefined","setup","focused","setFocused","listeners","forEach","isFocused","globalThis","document","visibilityState","focusManager"],"mappings":";;;AAOO,MAAMA,YAAY,SAASC,YAAY,CAAC;AAC7C,EAAA,QAAQ,CAAA;AACR,EAAA,QAAQ,CAAA;AAER,EAAA,MAAM,CAAA;AAENC,EAAAA,WAAW,GAAG;AACZ,IAAA,KAAK,EAAE,CAAA;AACP,IAAA,IAAI,CAAC,MAAM,GAAIC,OAAO,IAAK;AACzB;AACA;AACA,MAAA,IAAI,CAACC,QAAQ,IAAIC,MAAM,CAACC,gBAAgB,EAAE;AACxC,QAAA,MAAMC,QAAQ,GAAG,MAAMJ,OAAO,EAAE,CAAA;AAChC;QACAE,MAAM,CAACC,gBAAgB,CAAC,kBAAkB,EAAEC,QAAQ,EAAE,KAAK,CAAC,CAAA;AAE5D,QAAA,OAAO,MAAM;AACX;AACAF,UAAAA,MAAM,CAACG,mBAAmB,CAAC,kBAAkB,EAAED,QAAQ,CAAC,CAAA;SACzD,CAAA;AACH,OAAA;AACA,MAAA,OAAA;KACD,CAAA;AACH,GAAA;AAEUE,EAAAA,WAAW,GAAS;AAC5B,IAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClB,MAAA,IAAI,CAACC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AACpC,KAAA;AACF,GAAA;AAEUC,EAAAA,aAAa,GAAG;AACxB,IAAA,IAAI,CAAC,IAAI,CAACC,YAAY,EAAE,EAAE;MACxB,IAAI,CAAC,QAAQ,IAAI,CAAA;AACjB,MAAA,IAAI,CAAC,QAAQ,GAAGC,SAAS,CAAA;AAC3B,KAAA;AACF,GAAA;EAEAH,gBAAgB,CAACI,KAAc,EAAQ;AACrC,IAAA,IAAI,CAAC,MAAM,GAAGA,KAAK,CAAA;IACnB,IAAI,CAAC,QAAQ,IAAI,CAAA;AACjB,IAAA,IAAI,CAAC,QAAQ,GAAGA,KAAK,CAAEC,OAAO,IAAK;AACjC,MAAA,IAAI,OAAOA,OAAO,KAAK,SAAS,EAAE;AAChC,QAAA,IAAI,CAACC,UAAU,CAACD,OAAO,CAAC,CAAA;AAC1B,OAAC,MAAM;QACL,IAAI,CAACZ,OAAO,EAAE,CAAA;AAChB,OAAA;AACF,KAAC,CAAC,CAAA;AACJ,GAAA;EAEAa,UAAU,CAACD,OAAiB,EAAQ;AAClC,IAAA,IAAI,CAAC,QAAQ,GAAGA,OAAO,CAAA;AAEvB,IAAA,IAAIA,OAAO,EAAE;MACX,IAAI,CAACZ,OAAO,EAAE,CAAA;AAChB,KAAA;AACF,GAAA;AAEAA,EAAAA,OAAO,GAAS;AACd,IAAA,IAAI,CAACc,SAAS,CAACC,OAAO,CAAEX,QAAQ,IAAK;AACnCA,MAAAA,QAAQ,EAAE,CAAA;AACZ,KAAC,CAAC,CAAA;AACJ,GAAA;AAEAY,EAAAA,SAAS,GAAY;AACnB,IAAA,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE;MACtC,OAAO,IAAI,CAAC,QAAQ,CAAA;AACtB,KAAA;;AAEA;AACA;AACA,IAAA,OAAOC,UAAU,CAACC,QAAQ,EAAEC,eAAe,KAAK,QAAQ,CAAA;AAC1D,GAAA;AACF,CAAA;AAEaC,MAAAA,YAAY,GAAG,IAAIvB,YAAY;;;;"}