@tanstack/react-query 5.0.0-alpha.6 → 5.0.0-alpha.61

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 (232) hide show
  1. package/build/codemods/__testfixtures__/default-import.input.tsx +94 -0
  2. package/build/codemods/__testfixtures__/default-import.output.tsx +96 -0
  3. package/build/codemods/__testfixtures__/named-import.input.tsx +96 -0
  4. package/build/codemods/__testfixtures__/named-import.output.tsx +98 -0
  5. package/build/codemods/__testfixtures__/namespaced-import.input.tsx +86 -0
  6. package/build/codemods/__testfixtures__/namespaced-import.output.tsx +88 -0
  7. package/build/codemods/__testfixtures__/parameter-is-identifier.input.tsx +49 -0
  8. package/build/codemods/__testfixtures__/parameter-is-identifier.output.tsx +49 -0
  9. package/build/codemods/__testfixtures__/parameter-is-object-expression.input.tsx +128 -0
  10. package/build/codemods/__testfixtures__/parameter-is-object-expression.output.tsx +175 -0
  11. package/build/codemods/__testfixtures__/replace-import-specifier.input.tsx +10 -0
  12. package/build/codemods/__testfixtures__/replace-import-specifier.output.tsx +10 -0
  13. package/build/codemods/__testfixtures__/type-arguments.input.tsx +25 -0
  14. package/build/codemods/__testfixtures__/type-arguments.output.tsx +31 -0
  15. package/build/codemods/__tests__/key-transformation.test.js +32 -0
  16. package/build/codemods/__tests__/replace-import-specifier.test.js +12 -0
  17. package/build/codemods/remove-overloads/__testfixtures__/default-import.input.tsx +199 -0
  18. package/build/codemods/remove-overloads/__testfixtures__/default-import.output.tsx +484 -0
  19. package/build/codemods/remove-overloads/__tests__/remove-overloads.test.js +6 -0
  20. package/build/codemods/remove-overloads/remove-overloads.js +59 -0
  21. package/build/codemods/remove-overloads/transformers/filter-aware-usage-transformer.js +153 -0
  22. package/build/codemods/remove-overloads/transformers/query-fn-aware-usage-transformer.js +188 -0
  23. package/build/codemods/remove-overloads/utils/index.js +124 -0
  24. package/build/codemods/remove-overloads/utils/unknown-usage-error.js +27 -0
  25. package/build/codemods/src/utils/index.js +205 -0
  26. package/build/codemods/src/v4/key-transformation.js +138 -0
  27. package/build/codemods/src/v4/replace-import-specifier.js +25 -0
  28. package/build/codemods/transformers/query-cache-transformer.js +116 -0
  29. package/build/codemods/transformers/query-client-transformer.js +48 -0
  30. package/build/codemods/transformers/use-query-like-transformer.js +32 -0
  31. package/build/codemods/utils/replacers/key-replacer.js +164 -0
  32. package/build/lib/HydrationBoundary.cjs +50 -0
  33. package/build/lib/{HydrationBoundary.mjs.map → HydrationBoundary.cjs.map} +1 -1
  34. package/build/lib/HydrationBoundary.d.ts +1 -0
  35. package/build/lib/HydrationBoundary.d.ts.map +1 -0
  36. package/build/lib/HydrationBoundary.js +9 -29
  37. package/build/lib/HydrationBoundary.js.map +1 -1
  38. package/build/lib/QueryClientProvider.cjs +54 -0
  39. package/build/lib/QueryClientProvider.cjs.map +1 -0
  40. package/build/lib/QueryClientProvider.d.ts +2 -1
  41. package/build/lib/QueryClientProvider.d.ts.map +1 -0
  42. package/build/lib/QueryClientProvider.js +7 -29
  43. package/build/lib/QueryClientProvider.js.map +1 -1
  44. package/build/lib/QueryErrorResetBoundary.cjs +60 -0
  45. package/build/lib/{QueryErrorResetBoundary.mjs.map → QueryErrorResetBoundary.cjs.map} +1 -1
  46. package/build/lib/QueryErrorResetBoundary.d.ts +2 -1
  47. package/build/lib/QueryErrorResetBoundary.d.ts.map +1 -0
  48. package/build/lib/QueryErrorResetBoundary.js +7 -28
  49. package/build/lib/QueryErrorResetBoundary.js.map +1 -1
  50. package/build/lib/__tests__/HydrationBoundary.test.d.ts +1 -0
  51. package/build/lib/__tests__/HydrationBoundary.test.d.ts.map +1 -0
  52. package/build/lib/__tests__/QueryClientProvider.test.d.ts +1 -0
  53. package/build/lib/__tests__/QueryClientProvider.test.d.ts.map +1 -0
  54. package/build/lib/__tests__/QueryResetErrorBoundary.test.d.ts +1 -0
  55. package/build/lib/__tests__/QueryResetErrorBoundary.test.d.ts.map +1 -0
  56. package/build/lib/__tests__/ssr-hydration.test.d.ts +1 -0
  57. package/build/lib/__tests__/ssr-hydration.test.d.ts.map +1 -0
  58. package/build/lib/__tests__/ssr.test.d.ts +1 -0
  59. package/build/lib/__tests__/ssr.test.d.ts.map +1 -0
  60. package/build/lib/__tests__/suspense.test.d.ts +1 -0
  61. package/build/lib/__tests__/suspense.test.d.ts.map +1 -0
  62. package/build/lib/__tests__/useInfiniteQuery.test.d.ts +1 -0
  63. package/build/lib/__tests__/useInfiniteQuery.test.d.ts.map +1 -0
  64. package/build/lib/__tests__/useInfiniteQuery.type.test.d.ts +1 -0
  65. package/build/lib/__tests__/useInfiniteQuery.type.test.d.ts.map +1 -0
  66. package/build/lib/__tests__/useIsFetching.test.d.ts +1 -0
  67. package/build/lib/__tests__/useIsFetching.test.d.ts.map +1 -0
  68. package/build/lib/__tests__/useMutation.test.d.ts +1 -0
  69. package/build/lib/__tests__/useMutation.test.d.ts.map +1 -0
  70. package/build/lib/__tests__/useMutationState.test.d.ts +1 -0
  71. package/build/lib/__tests__/useMutationState.test.d.ts.map +1 -0
  72. package/build/lib/__tests__/useQueries.test.d.ts +1 -0
  73. package/build/lib/__tests__/useQueries.test.d.ts.map +1 -0
  74. package/build/lib/__tests__/useQuery.test.d.ts +1 -0
  75. package/build/lib/__tests__/useQuery.test.d.ts.map +1 -0
  76. package/build/lib/__tests__/useQuery.types.test.d.ts +1 -0
  77. package/build/lib/__tests__/useQuery.types.test.d.ts.map +1 -0
  78. package/build/lib/__tests__/utils.d.ts +6 -5
  79. package/build/lib/__tests__/utils.d.ts.map +1 -0
  80. package/build/lib/errorBoundaryUtils.cjs +51 -0
  81. package/build/lib/errorBoundaryUtils.cjs.map +1 -0
  82. package/build/lib/errorBoundaryUtils.d.ts +4 -3
  83. package/build/lib/errorBoundaryUtils.d.ts.map +1 -0
  84. package/build/lib/errorBoundaryUtils.js +8 -30
  85. package/build/lib/errorBoundaryUtils.js.map +1 -1
  86. package/build/lib/index.cjs +39 -0
  87. package/build/lib/index.cjs.map +1 -0
  88. package/build/lib/index.d.ts +2 -1
  89. package/build/lib/index.d.ts.map +1 -0
  90. package/build/lib/index.js +11 -37
  91. package/build/lib/index.js.map +1 -1
  92. package/build/lib/isRestoring.cjs +31 -0
  93. package/build/lib/isRestoring.cjs.map +1 -0
  94. package/build/lib/isRestoring.d.ts +1 -0
  95. package/build/lib/isRestoring.d.ts.map +1 -0
  96. package/build/lib/isRestoring.js +5 -26
  97. package/build/lib/isRestoring.js.map +1 -1
  98. package/build/lib/{suspense.mjs → suspense.cjs} +8 -10
  99. package/build/lib/suspense.cjs.map +1 -0
  100. package/build/lib/suspense.d.ts +3 -5
  101. package/build/lib/suspense.d.ts.map +1 -0
  102. package/build/lib/suspense.js +3 -15
  103. package/build/lib/suspense.js.map +1 -1
  104. package/build/lib/types.d.ts +11 -10
  105. package/build/lib/types.d.ts.map +1 -0
  106. package/build/lib/useBaseQuery.cjs +80 -0
  107. package/build/lib/useBaseQuery.cjs.map +1 -0
  108. package/build/lib/useBaseQuery.d.ts +1 -0
  109. package/build/lib/useBaseQuery.d.ts.map +1 -0
  110. package/build/lib/useBaseQuery.js +30 -54
  111. package/build/lib/useBaseQuery.js.map +1 -1
  112. package/build/lib/useInfiniteQuery.cjs +15 -0
  113. package/build/lib/useInfiniteQuery.cjs.map +1 -0
  114. package/build/lib/useInfiniteQuery.d.ts +1 -0
  115. package/build/lib/useInfiniteQuery.d.ts.map +1 -0
  116. package/build/lib/useInfiniteQuery.js +6 -7
  117. package/build/lib/useInfiniteQuery.js.map +1 -1
  118. package/build/lib/useIsFetching.cjs +34 -0
  119. package/build/lib/useIsFetching.cjs.map +1 -0
  120. package/build/lib/useIsFetching.d.ts +1 -0
  121. package/build/lib/useIsFetching.d.ts.map +1 -0
  122. package/build/lib/useIsFetching.js +7 -27
  123. package/build/lib/useIsFetching.js.map +1 -1
  124. package/build/lib/useMutation.cjs +54 -0
  125. package/build/lib/useMutation.cjs.map +1 -0
  126. package/build/lib/useMutation.d.ts +1 -0
  127. package/build/lib/useMutation.d.ts.map +1 -0
  128. package/build/lib/useMutation.js +12 -32
  129. package/build/lib/useMutation.js.map +1 -1
  130. package/build/lib/useMutationState.cjs +60 -0
  131. package/build/lib/useMutationState.cjs.map +1 -0
  132. package/build/lib/useMutationState.d.ts +4 -3
  133. package/build/lib/useMutationState.d.ts.map +1 -0
  134. package/build/lib/useMutationState.js +13 -34
  135. package/build/lib/useMutationState.js.map +1 -1
  136. package/build/lib/useQueries.cjs +99 -0
  137. package/build/lib/useQueries.cjs.map +1 -0
  138. package/build/lib/useQueries.d.ts +10 -8
  139. package/build/lib/useQueries.d.ts.map +1 -0
  140. package/build/lib/useQueries.js +52 -67
  141. package/build/lib/useQueries.js.map +1 -1
  142. package/build/lib/useQuery.cjs +19 -0
  143. package/build/lib/useQuery.cjs.map +1 -0
  144. package/build/lib/useQuery.d.ts +5 -2
  145. package/build/lib/useQuery.d.ts.map +1 -0
  146. package/build/lib/useQuery.js +8 -5
  147. package/build/lib/useQuery.js.map +1 -1
  148. package/build/lib/{utils.esm.js → utils.cjs} +4 -2
  149. package/build/lib/{utils.mjs.map → utils.cjs.map} +1 -1
  150. package/build/lib/utils.d.ts +1 -0
  151. package/build/lib/utils.d.ts.map +1 -0
  152. package/build/lib/utils.js +1 -3
  153. package/build/lib/utils.js.map +1 -1
  154. package/package.json +24 -15
  155. package/src/__tests__/QueryResetErrorBoundary.test.tsx +752 -620
  156. package/src/__tests__/ssr-hydration.test.tsx +2 -2
  157. package/src/__tests__/suspense.test.tsx +6 -88
  158. package/src/__tests__/useInfiniteQuery.type.test.tsx +0 -27
  159. package/src/__tests__/useMutation.test.tsx +4 -4
  160. package/src/__tests__/useMutationState.test.tsx +23 -0
  161. package/src/__tests__/useQueries.test.tsx +206 -83
  162. package/src/__tests__/useQuery.test.tsx +246 -338
  163. package/src/__tests__/useQuery.types.test.tsx +21 -1
  164. package/src/errorBoundaryUtils.ts +6 -5
  165. package/src/index.ts +1 -1
  166. package/src/suspense.ts +9 -15
  167. package/src/useBaseQuery.ts +12 -23
  168. package/src/useInfiniteQuery.ts +1 -0
  169. package/src/useIsFetching.ts +1 -0
  170. package/src/useMutation.ts +2 -1
  171. package/src/useMutationState.ts +4 -3
  172. package/src/useQueries.ts +44 -26
  173. package/src/useQuery.ts +23 -0
  174. package/build/lib/HydrationBoundary.esm.js +0 -28
  175. package/build/lib/HydrationBoundary.esm.js.map +0 -1
  176. package/build/lib/HydrationBoundary.mjs +0 -28
  177. package/build/lib/QueryClientProvider.esm.js +0 -30
  178. package/build/lib/QueryClientProvider.esm.js.map +0 -1
  179. package/build/lib/QueryClientProvider.mjs +0 -30
  180. package/build/lib/QueryClientProvider.mjs.map +0 -1
  181. package/build/lib/QueryErrorResetBoundary.esm.js +0 -37
  182. package/build/lib/QueryErrorResetBoundary.esm.js.map +0 -1
  183. package/build/lib/QueryErrorResetBoundary.mjs +0 -37
  184. package/build/lib/errorBoundaryUtils.esm.js +0 -27
  185. package/build/lib/errorBoundaryUtils.esm.js.map +0 -1
  186. package/build/lib/errorBoundaryUtils.mjs +0 -27
  187. package/build/lib/errorBoundaryUtils.mjs.map +0 -1
  188. package/build/lib/index.esm.js +0 -12
  189. package/build/lib/index.esm.js.map +0 -1
  190. package/build/lib/index.mjs +0 -12
  191. package/build/lib/index.mjs.map +0 -1
  192. package/build/lib/isRestoring.esm.js +0 -8
  193. package/build/lib/isRestoring.esm.js.map +0 -1
  194. package/build/lib/isRestoring.mjs +0 -8
  195. package/build/lib/isRestoring.mjs.map +0 -1
  196. package/build/lib/suspense.esm.js +0 -24
  197. package/build/lib/suspense.esm.js.map +0 -1
  198. package/build/lib/suspense.mjs.map +0 -1
  199. package/build/lib/useBaseQuery.esm.js +0 -62
  200. package/build/lib/useBaseQuery.esm.js.map +0 -1
  201. package/build/lib/useBaseQuery.mjs +0 -62
  202. package/build/lib/useBaseQuery.mjs.map +0 -1
  203. package/build/lib/useInfiniteQuery.esm.js +0 -12
  204. package/build/lib/useInfiniteQuery.esm.js.map +0 -1
  205. package/build/lib/useInfiniteQuery.mjs +0 -12
  206. package/build/lib/useInfiniteQuery.mjs.map +0 -1
  207. package/build/lib/useIsFetching.esm.js +0 -12
  208. package/build/lib/useIsFetching.esm.js.map +0 -1
  209. package/build/lib/useIsFetching.mjs +0 -12
  210. package/build/lib/useIsFetching.mjs.map +0 -1
  211. package/build/lib/useMutation.esm.js +0 -32
  212. package/build/lib/useMutation.esm.js.map +0 -1
  213. package/build/lib/useMutation.mjs +0 -32
  214. package/build/lib/useMutation.mjs.map +0 -1
  215. package/build/lib/useMutationState.esm.js +0 -37
  216. package/build/lib/useMutationState.esm.js.map +0 -1
  217. package/build/lib/useMutationState.mjs +0 -37
  218. package/build/lib/useMutationState.mjs.map +0 -1
  219. package/build/lib/useQueries.esm.js +0 -72
  220. package/build/lib/useQueries.esm.js.map +0 -1
  221. package/build/lib/useQueries.mjs +0 -69
  222. package/build/lib/useQueries.mjs.map +0 -1
  223. package/build/lib/useQuery.esm.js +0 -11
  224. package/build/lib/useQuery.esm.js.map +0 -1
  225. package/build/lib/useQuery.mjs +0 -11
  226. package/build/lib/useQuery.mjs.map +0 -1
  227. package/build/lib/utils.esm.js.map +0 -1
  228. package/build/lib/utils.mjs +0 -10
  229. package/build/umd/index.development.js +0 -3040
  230. package/build/umd/index.development.js.map +0 -1
  231. package/build/umd/index.production.js +0 -2
  232. package/build/umd/index.production.js.map +0 -1
@@ -64,23 +64,17 @@ describe('useQuery', () => {
64
64
  useQuery({
65
65
  queryKey: [key],
66
66
  queryFn: async () => true,
67
- onSuccess: (data) => expectType<boolean>(data),
68
- onSettled: (data) => expectType<boolean | undefined>(data),
69
67
  })
70
68
 
71
69
  // it should be possible to specify a union type as result type
72
70
  const unionTypeSync = useQuery({
73
71
  queryKey: key,
74
72
  queryFn: () => (Math.random() > 0.5 ? 'a' : 'b'),
75
-
76
- onSuccess: (data) => expectType<'a' | 'b'>(data),
77
73
  })
78
74
  expectType<'a' | 'b' | undefined>(unionTypeSync.data)
79
75
  const unionTypeAsync = useQuery<'a' | 'b'>({
80
76
  queryKey: key,
81
77
  queryFn: () => Promise.resolve(Math.random() > 0.5 ? 'a' : 'b'),
82
-
83
- onSuccess: (data) => expectType<'a' | 'b'>(data),
84
78
  })
85
79
  expectType<'a' | 'b' | undefined>(unionTypeAsync.data)
86
80
 
@@ -450,255 +444,6 @@ describe('useQuery', () => {
450
444
  })
451
445
  })
452
446
 
453
- it('should call onSuccess after a query has been fetched', async () => {
454
- const key = queryKey()
455
- const states: UseQueryResult<string>[] = []
456
- const onSuccess = vi.fn()
457
-
458
- function Page() {
459
- const state = useQuery({
460
- queryKey: key,
461
- queryFn: async () => {
462
- await sleep(10)
463
- return 'data'
464
- },
465
- onSuccess,
466
- })
467
- states.push(state)
468
- return <div>data: {state.data}</div>
469
- }
470
-
471
- const rendered = renderWithClient(queryClient, <Page />)
472
-
473
- await rendered.findByText('data: data')
474
- expect(states.length).toBe(2)
475
- expect(onSuccess).toHaveBeenCalledTimes(1)
476
- expect(onSuccess).toHaveBeenCalledWith('data')
477
- })
478
-
479
- it('should call onSuccess after a query has been refetched', async () => {
480
- const key = queryKey()
481
- const states: UseQueryResult<string>[] = []
482
- const onSuccess = vi.fn()
483
- let count = 0
484
-
485
- function Page() {
486
- const state = useQuery({
487
- queryKey: key,
488
- queryFn: async () => {
489
- count++
490
- await sleep(10)
491
- return 'data' + count
492
- },
493
- onSuccess,
494
- })
495
-
496
- states.push(state)
497
-
498
- return (
499
- <div>
500
- <div>data: {state.data}</div>
501
- <button onClick={() => state.refetch()}>refetch</button>
502
- </div>
503
- )
504
- }
505
-
506
- const rendered = renderWithClient(queryClient, <Page />)
507
-
508
- await rendered.findByText('data: data1')
509
- fireEvent.click(rendered.getByRole('button', { name: /refetch/i }))
510
- await rendered.findByText('data: data2')
511
-
512
- expect(states.length).toBe(3) //pending, success, success after refetch
513
- expect(count).toBe(2)
514
- expect(onSuccess).toHaveBeenCalledTimes(2)
515
- })
516
-
517
- it('should call onSuccess after a disabled query has been fetched', async () => {
518
- const key = queryKey()
519
- const states: UseQueryResult<string>[] = []
520
- const onSuccess = vi.fn()
521
-
522
- function Page() {
523
- const state = useQuery({
524
- queryKey: key,
525
- queryFn: () => 'data',
526
- enabled: false,
527
- onSuccess,
528
- })
529
-
530
- states.push(state)
531
-
532
- return (
533
- <div>
534
- <div>isSuccess: {state.isSuccess ? 'true' : 'false'}</div>
535
- <button onClick={() => state.refetch()}>refetch</button>
536
- </div>
537
- )
538
- }
539
-
540
- const rendered = renderWithClient(queryClient, <Page />)
541
-
542
- await waitFor(() => {
543
- rendered.getByText('isSuccess: false')
544
- })
545
-
546
- fireEvent.click(rendered.getByRole('button', { name: 'refetch' }))
547
-
548
- await waitFor(() => {
549
- rendered.getByText('isSuccess: true')
550
- })
551
-
552
- expect(onSuccess).toHaveBeenCalledTimes(1)
553
- expect(onSuccess).toHaveBeenCalledWith('data')
554
- })
555
-
556
- it('should not call onSuccess if a component has unmounted', async () => {
557
- const key = queryKey()
558
- const states: UseQueryResult<string>[] = []
559
- const onSuccess = vi.fn()
560
-
561
- function Page() {
562
- const [show, setShow] = React.useState(true)
563
-
564
- React.useEffect(() => {
565
- setShow(false)
566
- }, [setShow])
567
-
568
- return show ? <Component /> : null
569
- }
570
-
571
- function Component() {
572
- const state = useQuery({
573
- queryKey: key,
574
- queryFn: async () => {
575
- await sleep(10)
576
- return 'data'
577
- },
578
- onSuccess,
579
- })
580
- states.push(state)
581
- return null
582
- }
583
-
584
- renderWithClient(queryClient, <Page />)
585
-
586
- await sleep(50)
587
- expect(states.length).toBe(1)
588
- expect(onSuccess).toHaveBeenCalledTimes(0)
589
- })
590
-
591
- it('should call onError after a query has been fetched with an error', async () => {
592
- const key = queryKey()
593
- const states: UseQueryResult<unknown>[] = []
594
- const onError = vi.fn()
595
-
596
- function Page() {
597
- const state = useQuery<unknown>({
598
- queryKey: key,
599
- queryFn: () => Promise.reject(new Error('error')),
600
- retry: false,
601
- onError,
602
- })
603
- states.push(state)
604
- return null
605
- }
606
-
607
- renderWithClient(queryClient, <Page />)
608
-
609
- await sleep(10)
610
- expect(states.length).toBe(2)
611
- expect(onError).toHaveBeenCalledTimes(1)
612
- expect(onError).toHaveBeenCalledWith(new Error('error'))
613
- })
614
-
615
- it('should not call onError when receiving a CancelledError', async () => {
616
- const key = queryKey()
617
- const onError = vi.fn()
618
-
619
- function Page() {
620
- const { status, fetchStatus } = useQuery({
621
- queryKey: key,
622
- queryFn: async () => {
623
- await sleep(10)
624
- return 23
625
- },
626
-
627
- onError,
628
- })
629
- return (
630
- <span>
631
- status: {status}, fetchStatus: {fetchStatus}
632
- </span>
633
- )
634
- }
635
-
636
- const rendered = renderWithClient(queryClient, <Page />)
637
-
638
- rendered.getByText('status: pending, fetchStatus: fetching')
639
-
640
- await queryClient.cancelQueries({ queryKey: key })
641
- // query cancellation will reset the query to it's initial state
642
- await waitFor(() =>
643
- rendered.getByText('status: pending, fetchStatus: idle'),
644
- )
645
- expect(onError).not.toHaveBeenCalled()
646
- })
647
-
648
- it('should call onSettled after a query has been fetched', async () => {
649
- const key = queryKey()
650
- const states: UseQueryResult<string>[] = []
651
- const onSettled = vi.fn()
652
-
653
- function Page() {
654
- const state = useQuery({
655
- queryKey: key,
656
- queryFn: () => 'data',
657
- onSettled,
658
- })
659
- states.push(state)
660
-
661
- return <div>data: {state.data}</div>
662
- }
663
-
664
- const rendered = renderWithClient(queryClient, <Page />)
665
-
666
- await waitFor(() => {
667
- rendered.getByText('data: data')
668
- })
669
-
670
- expect(states.length).toBe(2)
671
- expect(onSettled).toHaveBeenCalledTimes(1)
672
- expect(onSettled).toHaveBeenCalledWith('data', null)
673
- })
674
-
675
- it('should call onSettled after a query has been fetched with an error', async () => {
676
- const key = queryKey()
677
- const onSettled = vi.fn()
678
- const error = new Error('error')
679
-
680
- function Page() {
681
- const state = useQuery({
682
- queryKey: key,
683
- queryFn: async () => {
684
- await sleep(10)
685
- return Promise.reject(error)
686
- },
687
- retry: false,
688
- onSettled,
689
- })
690
- return <div>status: {state.status}</div>
691
- }
692
-
693
- const rendered = renderWithClient(queryClient, <Page />)
694
-
695
- await waitFor(() => {
696
- rendered.getByText('status: error')
697
- })
698
- expect(onSettled).toHaveBeenCalledTimes(1)
699
- expect(onSettled).toHaveBeenCalledWith(undefined, error)
700
- })
701
-
702
447
  it('should not cancel an ongoing fetch when refetch is called with cancelRefetch=false if we have data already', async () => {
703
448
  const key = queryKey()
704
449
  let fetchCount = 0
@@ -1728,6 +1473,213 @@ describe('useQuery', () => {
1728
1473
  })
1729
1474
  })
1730
1475
 
1476
+ it('should keep the previous data when placeholderData is set and select fn transform is used', async () => {
1477
+ const key = queryKey()
1478
+ const states: UseQueryResult<number>[] = []
1479
+
1480
+ function Page() {
1481
+ const [count, setCount] = React.useState(0)
1482
+
1483
+ const state = useQuery({
1484
+ queryKey: [key, count],
1485
+ queryFn: async () => {
1486
+ await sleep(10)
1487
+ return {
1488
+ count,
1489
+ }
1490
+ },
1491
+ select(data) {
1492
+ return data.count
1493
+ },
1494
+ placeholderData: keepPreviousData,
1495
+ })
1496
+
1497
+ states.push(state)
1498
+
1499
+ return (
1500
+ <div>
1501
+ <div>data: {state.data}</div>
1502
+ <button onClick={() => setCount(1)}>setCount</button>
1503
+ </div>
1504
+ )
1505
+ }
1506
+
1507
+ const rendered = renderWithClient(queryClient, <Page />)
1508
+
1509
+ await waitFor(() => rendered.getByText('data: 0'))
1510
+
1511
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1512
+
1513
+ await waitFor(() => rendered.getByText('data: 1'))
1514
+
1515
+ // Initial
1516
+ expect(states[0]).toMatchObject({
1517
+ data: undefined,
1518
+ isFetching: true,
1519
+ isSuccess: false,
1520
+ isPlaceholderData: false,
1521
+ })
1522
+ // Fetched
1523
+ expect(states[1]).toMatchObject({
1524
+ data: 0,
1525
+ isFetching: false,
1526
+ isSuccess: true,
1527
+ isPlaceholderData: false,
1528
+ })
1529
+ // Set state
1530
+ expect(states[2]).toMatchObject({
1531
+ data: 0,
1532
+ isFetching: true,
1533
+ isSuccess: true,
1534
+ isPlaceholderData: true,
1535
+ })
1536
+ // New data
1537
+ expect(states[3]).toMatchObject({
1538
+ data: 1,
1539
+ isFetching: false,
1540
+ isSuccess: true,
1541
+ isPlaceholderData: false,
1542
+ })
1543
+ })
1544
+
1545
+ it('should keep the previous queryKey (from prevQuery) between multiple pending queries when placeholderData is set and select fn transform is used', async () => {
1546
+ const keys: Array<readonly unknown[] | null> = []
1547
+ const key = queryKey()
1548
+ const states: UseQueryResult<number>[] = []
1549
+
1550
+ function Page() {
1551
+ const [count, setCount] = React.useState(0)
1552
+
1553
+ const state = useQuery({
1554
+ queryKey: [key, count],
1555
+ queryFn: async () => {
1556
+ await sleep(10)
1557
+ return {
1558
+ count,
1559
+ }
1560
+ },
1561
+ select(data) {
1562
+ return data.count
1563
+ },
1564
+ placeholderData: (prevData, prevQuery) => {
1565
+ if (prevQuery) {
1566
+ keys.push(prevQuery.queryKey)
1567
+ }
1568
+ return prevData
1569
+ },
1570
+ })
1571
+
1572
+ states.push(state)
1573
+
1574
+ return (
1575
+ <div>
1576
+ <div>data: {state.data}</div>
1577
+ <button onClick={() => setCount((prev) => prev + 1)}>setCount</button>
1578
+ </div>
1579
+ )
1580
+ }
1581
+
1582
+ const rendered = renderWithClient(queryClient, <Page />)
1583
+
1584
+ await waitFor(() => rendered.getByText('data: 0'))
1585
+
1586
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1587
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1588
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1589
+
1590
+ await waitFor(() => rendered.getByText('data: 3'))
1591
+
1592
+ const allPreviousKeysAreTheFirstQueryKey = keys.every(
1593
+ (k) => JSON.stringify(k) === JSON.stringify([key, 0]),
1594
+ )
1595
+
1596
+ expect(allPreviousKeysAreTheFirstQueryKey).toBe(true)
1597
+ })
1598
+
1599
+ it('should show placeholderData between multiple pending queries when select fn transform is used', async () => {
1600
+ const key = queryKey()
1601
+ const states: UseQueryResult<number>[] = []
1602
+
1603
+ function Page() {
1604
+ const [count, setCount] = React.useState(0)
1605
+
1606
+ const state = useQuery({
1607
+ queryKey: [key, count],
1608
+ queryFn: async () => {
1609
+ await sleep(10)
1610
+ return {
1611
+ count,
1612
+ }
1613
+ },
1614
+ select(data) {
1615
+ return data.count
1616
+ },
1617
+ placeholderData: keepPreviousData,
1618
+ })
1619
+
1620
+ states.push(state)
1621
+
1622
+ return (
1623
+ <div>
1624
+ <div>data: {state.data}</div>
1625
+ <button onClick={() => setCount((prev) => prev + 1)}>setCount</button>
1626
+ </div>
1627
+ )
1628
+ }
1629
+
1630
+ const rendered = renderWithClient(queryClient, <Page />)
1631
+
1632
+ await waitFor(() => rendered.getByText('data: 0'))
1633
+
1634
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1635
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1636
+ fireEvent.click(rendered.getByRole('button', { name: 'setCount' }))
1637
+
1638
+ await waitFor(() => rendered.getByText('data: 3'))
1639
+ // Initial
1640
+ expect(states[0]).toMatchObject({
1641
+ data: undefined,
1642
+ isFetching: true,
1643
+ isSuccess: false,
1644
+ isPlaceholderData: false,
1645
+ })
1646
+ // Fetched
1647
+ expect(states[1]).toMatchObject({
1648
+ data: 0,
1649
+ isFetching: false,
1650
+ isSuccess: true,
1651
+ isPlaceholderData: false,
1652
+ })
1653
+ // Set state -> count = 1
1654
+ expect(states[2]).toMatchObject({
1655
+ data: 0,
1656
+ isFetching: true,
1657
+ isSuccess: true,
1658
+ isPlaceholderData: true,
1659
+ })
1660
+ // Set state -> count = 2
1661
+ expect(states[3]).toMatchObject({
1662
+ data: 0,
1663
+ isFetching: true,
1664
+ isSuccess: true,
1665
+ isPlaceholderData: true,
1666
+ })
1667
+ // Set state -> count = 3
1668
+ expect(states[4]).toMatchObject({
1669
+ data: 0,
1670
+ isFetching: true,
1671
+ isSuccess: true,
1672
+ isPlaceholderData: true,
1673
+ })
1674
+ // New data
1675
+ expect(states[5]).toMatchObject({
1676
+ data: 3,
1677
+ isFetching: false,
1678
+ isSuccess: true,
1679
+ isPlaceholderData: false,
1680
+ })
1681
+ })
1682
+
1731
1683
  it('should transition to error state when placeholderData is set', async () => {
1732
1684
  const key = queryKey()
1733
1685
  const states: UseQueryResult<number>[] = []
@@ -2434,53 +2386,6 @@ describe('useQuery', () => {
2434
2386
  expect(renders).toBe(2)
2435
2387
  })
2436
2388
 
2437
- it('should batch re-renders including hook callbacks', async () => {
2438
- const key = queryKey()
2439
-
2440
- let renders = 0
2441
- let callbackCount = 0
2442
-
2443
- const queryFn = async () => {
2444
- await sleep(10)
2445
- return 'data'
2446
- }
2447
-
2448
- function Page() {
2449
- const [count, setCount] = React.useState(0)
2450
- useQuery({
2451
- queryKey: key,
2452
- queryFn,
2453
- onSuccess: () => {
2454
- setCount((x) => x + 1)
2455
- },
2456
- })
2457
- useQuery({
2458
- queryKey: key,
2459
- queryFn,
2460
- onSuccess: () => {
2461
- setCount((x) => x + 1)
2462
- },
2463
- })
2464
-
2465
- React.useEffect(() => {
2466
- renders++
2467
- callbackCount = count
2468
- })
2469
-
2470
- return <div>count: {count}</div>
2471
- }
2472
-
2473
- const rendered = renderWithClient(queryClient, <Page />)
2474
-
2475
- await waitFor(() => rendered.getByText('count: 2'))
2476
-
2477
- // Should be 3 instead of 5
2478
- expect(renders).toBe(3)
2479
-
2480
- // Both callbacks should have been executed
2481
- expect(callbackCount).toBe(2)
2482
- })
2483
-
2484
2389
  it('should render latest data even if react has discarded certain renders', async () => {
2485
2390
  const key = queryKey()
2486
2391
 
@@ -2896,7 +2801,7 @@ describe('useQuery', () => {
2896
2801
  await waitFor(() => rendered.getByText('Error test jaylen'))
2897
2802
  })
2898
2803
 
2899
- it('should throw error if queryFn throws and throwErrors is in use', async () => {
2804
+ it('should throw error if queryFn throws and throwOnError is in use', async () => {
2900
2805
  const consoleMock = vi
2901
2806
  .spyOn(console, 'error')
2902
2807
  .mockImplementation(() => undefined)
@@ -2907,7 +2812,7 @@ describe('useQuery', () => {
2907
2812
  queryKey: key,
2908
2813
  queryFn: () => Promise.reject(new Error('Error test jaylen')),
2909
2814
  retry: false,
2910
- throwErrors: true,
2815
+ throwOnError: true,
2911
2816
  })
2912
2817
 
2913
2818
  return (
@@ -2929,7 +2834,7 @@ describe('useQuery', () => {
2929
2834
  consoleMock.mockRestore()
2930
2835
  })
2931
2836
 
2932
- it('should update with data if we observe no properties and throwErrors', async () => {
2837
+ it('should update with data if we observe no properties and throwOnError', async () => {
2933
2838
  const key = queryKey()
2934
2839
 
2935
2840
  let result: UseQueryResult<string> | undefined
@@ -2938,7 +2843,7 @@ describe('useQuery', () => {
2938
2843
  const query = useQuery({
2939
2844
  queryKey: key,
2940
2845
  queryFn: () => Promise.resolve('data'),
2941
- throwErrors: true,
2846
+ throwOnError: true,
2942
2847
  })
2943
2848
 
2944
2849
  React.useEffect(() => {
@@ -2966,7 +2871,7 @@ describe('useQuery', () => {
2966
2871
  queryFn: () => Promise.reject(new Error('Local Error')),
2967
2872
 
2968
2873
  retry: false,
2969
- throwErrors: (err) => err.message !== 'Local Error',
2874
+ throwOnError: (err) => err.message !== 'Local Error',
2970
2875
  })
2971
2876
 
2972
2877
  return (
@@ -3001,7 +2906,7 @@ describe('useQuery', () => {
3001
2906
  queryFn: () => Promise.reject(new Error('Remote Error')),
3002
2907
 
3003
2908
  retry: false,
3004
- throwErrors: (err) => err.message !== 'Local Error',
2909
+ throwOnError: (err) => err.message !== 'Local Error',
3005
2910
  })
3006
2911
 
3007
2912
  return (
@@ -5973,36 +5878,6 @@ describe('useQuery', () => {
5973
5878
  })
5974
5879
  })
5975
5880
 
5976
- it('setQueryData - should not call onSuccess callback of active observers', async () => {
5977
- const key = queryKey()
5978
- const onSuccess = vi.fn()
5979
-
5980
- function Page() {
5981
- const state = useQuery({
5982
- queryKey: key,
5983
- queryFn: () => 'data',
5984
- onSuccess,
5985
- })
5986
- return (
5987
- <div>
5988
- <div>data: {state.data}</div>
5989
- <button onClick={() => queryClient.setQueryData(key, 'newData')}>
5990
- setQueryData
5991
- </button>
5992
- </div>
5993
- )
5994
- }
5995
-
5996
- const rendered = renderWithClient(queryClient, <Page />)
5997
-
5998
- await waitFor(() => rendered.getByText('data: data'))
5999
- fireEvent.click(rendered.getByRole('button', { name: /setQueryData/i }))
6000
- await waitFor(() => rendered.getByText('data: newData'))
6001
-
6002
- expect(onSuccess).toHaveBeenCalledTimes(1)
6003
- expect(onSuccess).toHaveBeenCalledWith('data')
6004
- })
6005
-
6006
5881
  it('setQueryData - should respect updatedAt', async () => {
6007
5882
  const key = queryKey()
6008
5883
 
@@ -6085,4 +5960,37 @@ describe('useQuery', () => {
6085
5960
 
6086
5961
  await waitFor(() => rendered.getByText('data: custom client'))
6087
5962
  })
5963
+
5964
+ it('should be notified of updates between create and subscribe', async () => {
5965
+ const key = queryKey()
5966
+
5967
+ function Page() {
5968
+ const mounted = React.useRef<boolean>(false)
5969
+ const { data, status } = useQuery({
5970
+ enabled: false,
5971
+ queryKey: key,
5972
+ queryFn: async () => {
5973
+ await sleep(10)
5974
+ return 5
5975
+ },
5976
+ })
5977
+
5978
+ // this simulates a synchronous update between the time the query is created
5979
+ // and the time it is subscribed to that could be missed otherwise
5980
+ if (!mounted.current) {
5981
+ mounted.current = true
5982
+ queryClient.setQueryData(key, 1)
5983
+ }
5984
+
5985
+ return (
5986
+ <div>
5987
+ <span>status: {status}</span>
5988
+ <span>data: {data}</span>
5989
+ </div>
5990
+ )
5991
+ }
5992
+ const rendered = renderWithClient(queryClient, <Page />)
5993
+ await waitFor(() => rendered.getByText('status: success'))
5994
+ await waitFor(() => rendered.getByText('data: 1'))
5995
+ })
6088
5996
  })
@@ -1,4 +1,4 @@
1
- import { useQuery } from '../useQuery'
1
+ import { queryOptions, useQuery } from '../useQuery'
2
2
  import type { Expect, Equal } from './utils'
3
3
  import { doNotExecute } from './utils'
4
4
 
@@ -23,6 +23,26 @@ describe('initialData', () => {
23
23
  })
24
24
  })
25
25
 
26
+ it('TData should be defined when passed through queryOptions', () => {
27
+ doNotExecute(() => {
28
+ const options = queryOptions({
29
+ queryKey: ['key'],
30
+ queryFn: () => {
31
+ return {
32
+ wow: true,
33
+ }
34
+ },
35
+ initialData: {
36
+ wow: true,
37
+ },
38
+ })
39
+ const { data } = useQuery(options)
40
+
41
+ const result: Expect<Equal<{ wow: boolean }, typeof data>> = true
42
+ return result
43
+ })
44
+ })
45
+
26
46
  it('TData should always be defined when initialData is provided as a function which ALWAYS returns the data', () => {
27
47
  doNotExecute(() => {
28
48
  const { data } = useQuery({