@tanstack/react-query 5.24.8 → 5.26.3
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/codemods/coverage/clover.xml +2 -2
- package/build/codemods/coverage/index.html +1 -1
- package/build/codemods/coverage/utils/index.html +1 -1
- package/build/codemods/coverage/utils/index.js.html +1 -1
- package/build/codemods/coverage/utils/transformers/index.html +1 -1
- package/build/codemods/coverage/utils/transformers/query-cache-transformer.js.html +1 -1
- package/build/codemods/coverage/utils/transformers/query-client-transformer.js.html +1 -1
- package/build/codemods/coverage/utils/transformers/use-query-like-transformer.js.html +1 -1
- package/build/codemods/coverage/v4/index.html +1 -1
- package/build/codemods/coverage/v4/key-transformation.js.html +1 -1
- package/build/codemods/coverage/v4/replace-import-specifier.js.html +1 -1
- package/build/codemods/coverage/v4/utils/replacers/index.html +1 -1
- package/build/codemods/coverage/v4/utils/replacers/key-replacer.js.html +1 -1
- package/build/codemods/coverage/v5/is-loading/index.html +1 -1
- package/build/codemods/coverage/v5/is-loading/is-loading.js.html +1 -1
- package/build/codemods/coverage/v5/keep-previous-data/index.html +1 -1
- package/build/codemods/coverage/v5/keep-previous-data/keep-previous-data.js.html +1 -1
- package/build/codemods/coverage/v5/keep-previous-data/utils/already-has-placeholder-data-property.js.html +1 -1
- package/build/codemods/coverage/v5/keep-previous-data/utils/index.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/index.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/remove-overloads.js.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/transformers/filter-aware-usage-transformer.js.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/transformers/index.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/transformers/query-fn-aware-usage-transformer.js.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/utils/index.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/utils/index.js.html +1 -1
- package/build/codemods/coverage/v5/remove-overloads/utils/unknown-usage-error.js.html +1 -1
- package/build/codemods/coverage/v5/rename-hydrate/index.html +1 -1
- package/build/codemods/coverage/v5/rename-hydrate/rename-hydrate.js.html +1 -1
- package/build/codemods/coverage/v5/rename-properties/index.html +1 -1
- package/build/codemods/coverage/v5/rename-properties/rename-properties.js.html +1 -1
- package/build/legacy/useQueries.cjs.map +1 -1
- package/build/legacy/useQueries.d.cts +5 -5
- package/build/legacy/useQueries.d.ts +5 -5
- package/build/legacy/useQueries.js.map +1 -1
- package/build/legacy/useSuspenseQueries.cjs.map +1 -1
- package/build/legacy/useSuspenseQueries.d.cts +3 -3
- package/build/legacy/useSuspenseQueries.d.ts +3 -3
- package/build/legacy/useSuspenseQueries.js.map +1 -1
- package/build/legacy/useSuspenseQuery.cjs +5 -0
- package/build/legacy/useSuspenseQuery.cjs.map +1 -1
- package/build/legacy/useSuspenseQuery.js +6 -1
- package/build/legacy/useSuspenseQuery.js.map +1 -1
- package/build/modern/useQueries.cjs.map +1 -1
- package/build/modern/useQueries.d.cts +5 -5
- package/build/modern/useQueries.d.ts +5 -5
- package/build/modern/useQueries.js.map +1 -1
- package/build/modern/useSuspenseQueries.cjs.map +1 -1
- package/build/modern/useSuspenseQueries.d.cts +3 -3
- package/build/modern/useSuspenseQueries.d.ts +3 -3
- package/build/modern/useSuspenseQueries.js.map +1 -1
- package/build/modern/useSuspenseQuery.cjs +5 -0
- package/build/modern/useSuspenseQuery.cjs.map +1 -1
- package/build/modern/useSuspenseQuery.js +6 -1
- package/build/modern/useSuspenseQuery.js.map +1 -1
- package/build/query-codemods/vite.config.ts +1 -0
- package/package.json +2 -2
- package/src/__tests__/infiniteQueryOptions.test-d.tsx +4 -10
- package/src/__tests__/queryOptions.test-d.tsx +24 -2
- package/src/__tests__/suspense.test-d.tsx +11 -0
- package/src/__tests__/useInfiniteQuery.test.tsx +34 -58
- package/src/__tests__/useMutation.test.tsx +43 -62
- package/src/__tests__/useQueries.test.tsx +106 -104
- package/src/__tests__/useQuery.test.tsx +97 -47
- package/src/__tests__/utils.tsx +3 -10
- package/src/useQueries.ts +11 -7
- package/src/useSuspenseQueries.ts +7 -5
- package/src/useSuspenseQuery.ts +7 -1
|
@@ -2,6 +2,7 @@ import { describe, expect, expectTypeOf, it, test, vi } from 'vitest'
|
|
|
2
2
|
import { act, fireEvent, render, waitFor } from '@testing-library/react'
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { ErrorBoundary } from 'react-error-boundary'
|
|
5
|
+
import { skipToken } from '@tanstack/query-core'
|
|
5
6
|
import { QueryCache, keepPreviousData, useQuery } from '..'
|
|
6
7
|
import {
|
|
7
8
|
Blink,
|
|
@@ -32,29 +33,29 @@ describe('useQuery', () => {
|
|
|
32
33
|
function Page() {
|
|
33
34
|
// unspecified query function should default to unknown
|
|
34
35
|
const noQueryFn = useQuery({ queryKey: key })
|
|
35
|
-
expectTypeOf
|
|
36
|
-
expectTypeOf
|
|
36
|
+
expectTypeOf(noQueryFn.data).toEqualTypeOf<unknown>()
|
|
37
|
+
expectTypeOf(noQueryFn.error).toEqualTypeOf<Error | null>()
|
|
37
38
|
|
|
38
39
|
// it should infer the result type from the query function
|
|
39
40
|
const fromQueryFn = useQuery({ queryKey: key, queryFn: () => 'test' })
|
|
40
|
-
expectTypeOf<string | undefined>(
|
|
41
|
-
expectTypeOf
|
|
41
|
+
expectTypeOf(fromQueryFn.data).toEqualTypeOf<string | undefined>()
|
|
42
|
+
expectTypeOf(fromQueryFn.error).toEqualTypeOf<Error | null>()
|
|
42
43
|
|
|
43
44
|
// it should be possible to specify the result type
|
|
44
45
|
const withResult = useQuery<string>({
|
|
45
46
|
queryKey: key,
|
|
46
47
|
queryFn: () => 'test',
|
|
47
48
|
})
|
|
48
|
-
expectTypeOf<string | undefined>(
|
|
49
|
-
expectTypeOf<
|
|
49
|
+
expectTypeOf(withResult.data).toEqualTypeOf<string | undefined>()
|
|
50
|
+
expectTypeOf(withResult.error).toEqualTypeOf<Error | null>()
|
|
50
51
|
|
|
51
52
|
// it should be possible to specify the error type
|
|
52
53
|
const withError = useQuery<string, Error>({
|
|
53
54
|
queryKey: key,
|
|
54
55
|
queryFn: () => 'test',
|
|
55
56
|
})
|
|
56
|
-
expectTypeOf<string | undefined>(
|
|
57
|
-
expectTypeOf<Error | null>(
|
|
57
|
+
expectTypeOf(withError.data).toEqualTypeOf<string | undefined>()
|
|
58
|
+
expectTypeOf(withError.error).toEqualTypeOf<Error | null>()
|
|
58
59
|
|
|
59
60
|
// it should provide the result type in the configuration
|
|
60
61
|
useQuery({
|
|
@@ -65,14 +66,14 @@ describe('useQuery', () => {
|
|
|
65
66
|
// it should be possible to specify a union type as result type
|
|
66
67
|
const unionTypeSync = useQuery({
|
|
67
68
|
queryKey: key,
|
|
68
|
-
queryFn: () => (Math.random() > 0.5 ? 'a' : 'b'),
|
|
69
|
+
queryFn: () => (Math.random() > 0.5 ? ('a' as const) : ('b' as const)),
|
|
69
70
|
})
|
|
70
|
-
expectTypeOf<'a' | 'b' | undefined>(
|
|
71
|
+
expectTypeOf(unionTypeSync.data).toEqualTypeOf<'a' | 'b' | undefined>()
|
|
71
72
|
const unionTypeAsync = useQuery<'a' | 'b'>({
|
|
72
73
|
queryKey: key,
|
|
73
74
|
queryFn: () => Promise.resolve(Math.random() > 0.5 ? 'a' : 'b'),
|
|
74
75
|
})
|
|
75
|
-
expectTypeOf<'a' | 'b' | undefined>(
|
|
76
|
+
expectTypeOf(unionTypeAsync.data).toEqualTypeOf<'a' | 'b' | undefined>()
|
|
76
77
|
|
|
77
78
|
// should error when the query function result does not match with the specified type
|
|
78
79
|
// @ts-expect-error
|
|
@@ -87,15 +88,19 @@ describe('useQuery', () => {
|
|
|
87
88
|
queryKey: key,
|
|
88
89
|
queryFn: () => queryFn(),
|
|
89
90
|
})
|
|
90
|
-
expectTypeOf<string | undefined>(
|
|
91
|
-
expectTypeOf
|
|
91
|
+
expectTypeOf(fromGenericQueryFn.data).toEqualTypeOf<string | undefined>()
|
|
92
|
+
expectTypeOf(fromGenericQueryFn.error).toEqualTypeOf<Error | null>()
|
|
92
93
|
|
|
93
94
|
const fromGenericOptionsQueryFn = useQuery({
|
|
94
95
|
queryKey: key,
|
|
95
96
|
queryFn: () => queryFn(),
|
|
96
97
|
})
|
|
97
|
-
expectTypeOf
|
|
98
|
-
|
|
98
|
+
expectTypeOf(fromGenericOptionsQueryFn.data).toEqualTypeOf<
|
|
99
|
+
string | undefined
|
|
100
|
+
>()
|
|
101
|
+
expectTypeOf(
|
|
102
|
+
fromGenericOptionsQueryFn.error,
|
|
103
|
+
).toEqualTypeOf<Error | null>()
|
|
99
104
|
|
|
100
105
|
type MyData = number
|
|
101
106
|
type MyQueryKey = readonly ['my-data', number]
|
|
@@ -114,7 +119,7 @@ describe('useQuery', () => {
|
|
|
114
119
|
const getMyDataStringKey: QueryFunction<MyData, ['1']> = async (
|
|
115
120
|
context,
|
|
116
121
|
) => {
|
|
117
|
-
expectTypeOf<['1']>(
|
|
122
|
+
expectTypeOf(context.queryKey).toEqualTypeOf<['1']>()
|
|
118
123
|
return Number(context.queryKey[0]) + 42
|
|
119
124
|
}
|
|
120
125
|
|
|
@@ -153,7 +158,7 @@ describe('useQuery', () => {
|
|
|
153
158
|
...options,
|
|
154
159
|
})
|
|
155
160
|
const testQuery = useWrappedQuery([''], async () => '1')
|
|
156
|
-
expectTypeOf<string | undefined>(
|
|
161
|
+
expectTypeOf(testQuery.data).toEqualTypeOf<string | undefined>()
|
|
157
162
|
|
|
158
163
|
// handles wrapped queries with custom fetcher passed directly to useQuery
|
|
159
164
|
const useWrappedFuncStyleQuery = <
|
|
@@ -170,7 +175,7 @@ describe('useQuery', () => {
|
|
|
170
175
|
>,
|
|
171
176
|
) => useQuery({ queryKey: qk, queryFn: fetcher, ...options })
|
|
172
177
|
const testFuncStyle = useWrappedFuncStyleQuery([''], async () => true)
|
|
173
|
-
expectTypeOf<boolean | undefined>(
|
|
178
|
+
expectTypeOf(testFuncStyle.data).toEqualTypeOf<boolean | undefined>()
|
|
174
179
|
}
|
|
175
180
|
})
|
|
176
181
|
|
|
@@ -217,19 +222,19 @@ describe('useQuery', () => {
|
|
|
217
222
|
states.push(state)
|
|
218
223
|
|
|
219
224
|
if (state.isPending) {
|
|
220
|
-
expectTypeOf
|
|
221
|
-
expectTypeOf
|
|
225
|
+
expectTypeOf(state.data).toEqualTypeOf<undefined>()
|
|
226
|
+
expectTypeOf(state.error).toEqualTypeOf<null>()
|
|
222
227
|
return <span>pending</span>
|
|
223
228
|
}
|
|
224
229
|
|
|
225
230
|
if (state.isLoadingError) {
|
|
226
|
-
expectTypeOf
|
|
227
|
-
expectTypeOf
|
|
231
|
+
expectTypeOf(state.data).toEqualTypeOf<undefined>()
|
|
232
|
+
expectTypeOf(state.error).toEqualTypeOf<Error>()
|
|
228
233
|
return <span>{state.error.message}</span>
|
|
229
234
|
}
|
|
230
235
|
|
|
231
|
-
expectTypeOf
|
|
232
|
-
expectTypeOf<Error | null>(
|
|
236
|
+
expectTypeOf(state.data).toEqualTypeOf<string>()
|
|
237
|
+
expectTypeOf(state.error).toEqualTypeOf<Error | null>()
|
|
233
238
|
return <span>{state.data}</span>
|
|
234
239
|
}
|
|
235
240
|
|
|
@@ -5211,12 +5216,11 @@ describe('useQuery', () => {
|
|
|
5211
5216
|
}
|
|
5212
5217
|
|
|
5213
5218
|
const rendered = renderWithClient(queryClient, <Page />)
|
|
5214
|
-
window.dispatchEvent(new Event('offline'))
|
|
5215
5219
|
|
|
5216
5220
|
await waitFor(() => rendered.getByText('status: pending, isPaused: true'))
|
|
5217
5221
|
|
|
5218
|
-
onlineMock.
|
|
5219
|
-
|
|
5222
|
+
onlineMock.mockReturnValue(true)
|
|
5223
|
+
queryClient.getQueryCache().onOnline()
|
|
5220
5224
|
|
|
5221
5225
|
await waitFor(() =>
|
|
5222
5226
|
rendered.getByText('status: success, isPaused: false'),
|
|
@@ -5226,6 +5230,7 @@ describe('useQuery', () => {
|
|
|
5226
5230
|
})
|
|
5227
5231
|
|
|
5228
5232
|
expect(states).toEqual(['paused', 'fetching', 'idle'])
|
|
5233
|
+
onlineMock.mockRestore()
|
|
5229
5234
|
})
|
|
5230
5235
|
|
|
5231
5236
|
it('online queries should not refetch if you are offline', async () => {
|
|
@@ -5264,7 +5269,6 @@ describe('useQuery', () => {
|
|
|
5264
5269
|
await waitFor(() => rendered.getByText('data: data1'))
|
|
5265
5270
|
|
|
5266
5271
|
const onlineMock = mockOnlineManagerIsOnline(false)
|
|
5267
|
-
window.dispatchEvent(new Event('offline'))
|
|
5268
5272
|
|
|
5269
5273
|
fireEvent.click(rendered.getByRole('button', { name: /invalidate/i }))
|
|
5270
5274
|
|
|
@@ -5275,8 +5279,8 @@ describe('useQuery', () => {
|
|
|
5275
5279
|
)
|
|
5276
5280
|
await waitFor(() => rendered.getByText('failureReason: null'))
|
|
5277
5281
|
|
|
5278
|
-
onlineMock.
|
|
5279
|
-
|
|
5282
|
+
onlineMock.mockReturnValue(true)
|
|
5283
|
+
queryClient.getQueryCache().onOnline()
|
|
5280
5284
|
|
|
5281
5285
|
await waitFor(() =>
|
|
5282
5286
|
rendered.getByText(
|
|
@@ -5294,6 +5298,8 @@ describe('useQuery', () => {
|
|
|
5294
5298
|
await waitFor(() => {
|
|
5295
5299
|
expect(rendered.getByText('data: data2')).toBeInTheDocument()
|
|
5296
5300
|
})
|
|
5301
|
+
|
|
5302
|
+
onlineMock.mockRestore()
|
|
5297
5303
|
})
|
|
5298
5304
|
|
|
5299
5305
|
it('online queries should not refetch if you are offline and refocus', async () => {
|
|
@@ -5483,7 +5489,6 @@ describe('useQuery', () => {
|
|
|
5483
5489
|
const onlineMock = mockOnlineManagerIsOnline(false)
|
|
5484
5490
|
|
|
5485
5491
|
const rendered = renderWithClient(queryClient, <Page />)
|
|
5486
|
-
window.dispatchEvent(new Event('offline'))
|
|
5487
5492
|
|
|
5488
5493
|
await waitFor(() =>
|
|
5489
5494
|
rendered.getByText('status: success, fetchStatus: paused'),
|
|
@@ -5506,10 +5511,8 @@ describe('useQuery', () => {
|
|
|
5506
5511
|
window.dispatchEvent(new Event('visibilitychange'))
|
|
5507
5512
|
})
|
|
5508
5513
|
|
|
5509
|
-
onlineMock.
|
|
5510
|
-
|
|
5511
|
-
window.dispatchEvent(new Event('online'))
|
|
5512
|
-
})
|
|
5514
|
+
onlineMock.mockReturnValue(true)
|
|
5515
|
+
queryClient.getQueryCache().onOnline()
|
|
5513
5516
|
|
|
5514
5517
|
await waitFor(() =>
|
|
5515
5518
|
rendered.getByText('status: success, fetchStatus: idle'),
|
|
@@ -5519,6 +5522,8 @@ describe('useQuery', () => {
|
|
|
5519
5522
|
})
|
|
5520
5523
|
|
|
5521
5524
|
expect(count).toBe(1)
|
|
5525
|
+
|
|
5526
|
+
onlineMock.mockRestore()
|
|
5522
5527
|
})
|
|
5523
5528
|
|
|
5524
5529
|
it('online queries should pause retries if you are offline', async () => {
|
|
@@ -5555,7 +5560,6 @@ describe('useQuery', () => {
|
|
|
5555
5560
|
)
|
|
5556
5561
|
|
|
5557
5562
|
const onlineMock = mockOnlineManagerIsOnline(false)
|
|
5558
|
-
window.dispatchEvent(new Event('offline'))
|
|
5559
5563
|
|
|
5560
5564
|
await sleep(20)
|
|
5561
5565
|
|
|
@@ -5569,7 +5573,7 @@ describe('useQuery', () => {
|
|
|
5569
5573
|
expect(count).toBe(1)
|
|
5570
5574
|
|
|
5571
5575
|
onlineMock.mockReturnValue(true)
|
|
5572
|
-
|
|
5576
|
+
queryClient.getQueryCache().onOnline()
|
|
5573
5577
|
|
|
5574
5578
|
await waitFor(() =>
|
|
5575
5579
|
rendered.getByText('status: error, fetchStatus: idle, failureCount: 3'),
|
|
@@ -5620,16 +5624,14 @@ describe('useQuery', () => {
|
|
|
5620
5624
|
|
|
5621
5625
|
const rendered = renderWithClient(queryClient, <Page />)
|
|
5622
5626
|
|
|
5623
|
-
window.dispatchEvent(new Event('offline'))
|
|
5624
|
-
|
|
5625
5627
|
await waitFor(() =>
|
|
5626
5628
|
rendered.getByText('status: pending, fetchStatus: paused'),
|
|
5627
5629
|
)
|
|
5628
5630
|
|
|
5629
5631
|
fireEvent.click(rendered.getByRole('button', { name: /hide/i }))
|
|
5630
5632
|
|
|
5631
|
-
onlineMock.
|
|
5632
|
-
|
|
5633
|
+
onlineMock.mockReturnValue(true)
|
|
5634
|
+
queryClient.getQueryCache().onOnline()
|
|
5633
5635
|
|
|
5634
5636
|
await waitFor(() => {
|
|
5635
5637
|
expect(queryClient.getQueryState(key)).toMatchObject({
|
|
@@ -5641,6 +5643,8 @@ describe('useQuery', () => {
|
|
|
5641
5643
|
// give it a bit more time to make sure queryFn is not called again
|
|
5642
5644
|
await sleep(15)
|
|
5643
5645
|
expect(count).toBe(1)
|
|
5646
|
+
|
|
5647
|
+
onlineMock.mockRestore()
|
|
5644
5648
|
})
|
|
5645
5649
|
|
|
5646
5650
|
it('online queries should not fetch if paused and we go online when cancelled and no refetchOnReconnect', async () => {
|
|
@@ -5690,7 +5694,7 @@ describe('useQuery', () => {
|
|
|
5690
5694
|
expect(count).toBe(0)
|
|
5691
5695
|
|
|
5692
5696
|
onlineMock.mockReturnValue(true)
|
|
5693
|
-
|
|
5697
|
+
queryClient.getQueryCache().onOnline()
|
|
5694
5698
|
|
|
5695
5699
|
await sleep(15)
|
|
5696
5700
|
|
|
@@ -5762,7 +5766,7 @@ describe('useQuery', () => {
|
|
|
5762
5766
|
await sleep(15)
|
|
5763
5767
|
|
|
5764
5768
|
onlineMock.mockReturnValue(true)
|
|
5765
|
-
|
|
5769
|
+
queryClient.getQueryCache().onOnline()
|
|
5766
5770
|
|
|
5767
5771
|
await sleep(15)
|
|
5768
5772
|
|
|
@@ -5896,8 +5900,6 @@ describe('useQuery', () => {
|
|
|
5896
5900
|
|
|
5897
5901
|
const rendered = renderWithClient(queryClient, <Page />)
|
|
5898
5902
|
|
|
5899
|
-
window.dispatchEvent(new Event('offline'))
|
|
5900
|
-
|
|
5901
5903
|
await waitFor(() =>
|
|
5902
5904
|
rendered.getByText(
|
|
5903
5905
|
'status: pending, fetchStatus: paused, failureCount: 1',
|
|
@@ -5907,8 +5909,8 @@ describe('useQuery', () => {
|
|
|
5907
5909
|
|
|
5908
5910
|
expect(count).toBe(1)
|
|
5909
5911
|
|
|
5910
|
-
onlineMock.
|
|
5911
|
-
|
|
5912
|
+
onlineMock.mockReturnValue(true)
|
|
5913
|
+
queryClient.getQueryCache().onOnline()
|
|
5912
5914
|
|
|
5913
5915
|
await waitFor(() =>
|
|
5914
5916
|
rendered.getByText('status: error, fetchStatus: idle, failureCount: 3'),
|
|
@@ -5916,6 +5918,7 @@ describe('useQuery', () => {
|
|
|
5916
5918
|
await waitFor(() => rendered.getByText('failureReason: failed3'))
|
|
5917
5919
|
|
|
5918
5920
|
expect(count).toBe(3)
|
|
5921
|
+
onlineMock.mockRestore()
|
|
5919
5922
|
})
|
|
5920
5923
|
})
|
|
5921
5924
|
|
|
@@ -6329,4 +6332,51 @@ describe('useQuery', () => {
|
|
|
6329
6332
|
expect(() => render(<Page />)).toThrow('Bad argument type')
|
|
6330
6333
|
consoleMock.mockRestore()
|
|
6331
6334
|
})
|
|
6335
|
+
|
|
6336
|
+
it('should respect skipToken and refetch when skipToken is taken away', async () => {
|
|
6337
|
+
const key = queryKey()
|
|
6338
|
+
|
|
6339
|
+
function Page({ enabled }: { enabled: boolean }) {
|
|
6340
|
+
const { data, status } = useQuery({
|
|
6341
|
+
queryKey: [key],
|
|
6342
|
+
queryFn: enabled
|
|
6343
|
+
? async () => {
|
|
6344
|
+
await sleep(10)
|
|
6345
|
+
|
|
6346
|
+
return Promise.resolve('data')
|
|
6347
|
+
}
|
|
6348
|
+
: skipToken,
|
|
6349
|
+
retry: false,
|
|
6350
|
+
retryOnMount: false,
|
|
6351
|
+
refetchOnMount: false,
|
|
6352
|
+
refetchOnWindowFocus: false,
|
|
6353
|
+
})
|
|
6354
|
+
|
|
6355
|
+
return (
|
|
6356
|
+
<div>
|
|
6357
|
+
<div>status: {status}</div>
|
|
6358
|
+
<div>data: {String(data)}</div>
|
|
6359
|
+
</div>
|
|
6360
|
+
)
|
|
6361
|
+
}
|
|
6362
|
+
|
|
6363
|
+
function App() {
|
|
6364
|
+
const [enabled, toggle] = React.useReducer((x) => !x, false)
|
|
6365
|
+
|
|
6366
|
+
return (
|
|
6367
|
+
<div>
|
|
6368
|
+
<Page enabled={enabled} />
|
|
6369
|
+
<button onClick={toggle}>enable</button>
|
|
6370
|
+
</div>
|
|
6371
|
+
)
|
|
6372
|
+
}
|
|
6373
|
+
|
|
6374
|
+
const rendered = renderWithClient(queryClient, <App />)
|
|
6375
|
+
|
|
6376
|
+
await waitFor(() => rendered.getByText('status: pending'))
|
|
6377
|
+
|
|
6378
|
+
fireEvent.click(rendered.getByRole('button', { name: 'enable' }))
|
|
6379
|
+
await waitFor(() => rendered.getByText('status: success'))
|
|
6380
|
+
await waitFor(() => rendered.getByText('data: data'))
|
|
6381
|
+
})
|
|
6332
6382
|
})
|
package/src/__tests__/utils.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { act, render } from '@testing-library/react'
|
|
|
4
4
|
import * as utils from '@tanstack/query-core'
|
|
5
5
|
import { QueryClient, QueryClientProvider, onlineManager } from '..'
|
|
6
6
|
import type { QueryClientConfig } from '..'
|
|
7
|
-
import type {
|
|
7
|
+
import type { MockInstance } from 'vitest'
|
|
8
8
|
|
|
9
9
|
export function renderWithClient(
|
|
10
10
|
client: QueryClient,
|
|
@@ -48,13 +48,13 @@ export function createQueryClient(config?: QueryClientConfig): QueryClient {
|
|
|
48
48
|
|
|
49
49
|
export function mockVisibilityState(
|
|
50
50
|
value: DocumentVisibilityState,
|
|
51
|
-
):
|
|
51
|
+
): MockInstance<[], DocumentVisibilityState> {
|
|
52
52
|
return vi.spyOn(document, 'visibilityState', 'get').mockReturnValue(value)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export function mockOnlineManagerIsOnline(
|
|
56
56
|
value: boolean,
|
|
57
|
-
):
|
|
57
|
+
): MockInstance<[], boolean> {
|
|
58
58
|
return vi.spyOn(onlineManager, 'isOnline').mockReturnValue(value)
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -78,13 +78,6 @@ export function setActTimeout(fn: () => void, ms?: number) {
|
|
|
78
78
|
}, ms)
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
/**
|
|
82
|
-
* Assert the parameter is not typed as `any`
|
|
83
|
-
*/
|
|
84
|
-
export function expectTypeNotAny<T>(_: 0 extends 1 & T ? never : T): void {
|
|
85
|
-
return undefined
|
|
86
|
-
}
|
|
87
|
-
|
|
88
81
|
// This monkey-patches the isServer-value from utils,
|
|
89
82
|
// so that we can pretend to be in a server environment
|
|
90
83
|
export function setIsServer(isServer: boolean) {
|
package/src/useQueries.ts
CHANGED
|
@@ -32,6 +32,7 @@ import type {
|
|
|
32
32
|
QueryClient,
|
|
33
33
|
QueryFunction,
|
|
34
34
|
QueryKey,
|
|
35
|
+
SkipToken,
|
|
35
36
|
ThrowOnError,
|
|
36
37
|
} from '@tanstack/query-core'
|
|
37
38
|
|
|
@@ -73,7 +74,9 @@ type GetOptions<T> =
|
|
|
73
74
|
? UseQueryOptionsForUseQueries<TQueryFnData>
|
|
74
75
|
: // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided
|
|
75
76
|
T extends {
|
|
76
|
-
queryFn?:
|
|
77
|
+
queryFn?:
|
|
78
|
+
| QueryFunction<infer TQueryFnData, infer TQueryKey>
|
|
79
|
+
| SkipToken
|
|
77
80
|
select?: (data: any) => infer TData
|
|
78
81
|
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
79
82
|
}
|
|
@@ -84,10 +87,9 @@ type GetOptions<T> =
|
|
|
84
87
|
TQueryKey
|
|
85
88
|
>
|
|
86
89
|
: T extends {
|
|
87
|
-
queryFn?:
|
|
88
|
-
infer TQueryFnData,
|
|
89
|
-
|
|
90
|
-
>
|
|
90
|
+
queryFn?:
|
|
91
|
+
| QueryFunction<infer TQueryFnData, infer TQueryKey>
|
|
92
|
+
| SkipToken
|
|
91
93
|
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
92
94
|
}
|
|
93
95
|
? UseQueryOptionsForUseQueries<
|
|
@@ -133,7 +135,7 @@ type GetResults<T> =
|
|
|
133
135
|
? GetDefinedOrUndefinedQueryResult<T, TQueryFnData>
|
|
134
136
|
: // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided
|
|
135
137
|
T extends {
|
|
136
|
-
queryFn?: QueryFunction<infer TQueryFnData, any>
|
|
138
|
+
queryFn?: QueryFunction<infer TQueryFnData, any> | SkipToken
|
|
137
139
|
select?: (data: any) => infer TData
|
|
138
140
|
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
139
141
|
}
|
|
@@ -143,7 +145,9 @@ type GetResults<T> =
|
|
|
143
145
|
unknown extends TError ? DefaultError : TError
|
|
144
146
|
>
|
|
145
147
|
: T extends {
|
|
146
|
-
queryFn?:
|
|
148
|
+
queryFn?:
|
|
149
|
+
| QueryFunction<infer TQueryFnData, any>
|
|
150
|
+
| SkipToken
|
|
147
151
|
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
148
152
|
}
|
|
149
153
|
? GetDefinedOrUndefinedQueryResult<
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
DefaultError,
|
|
7
7
|
QueryClient,
|
|
8
8
|
QueryFunction,
|
|
9
|
+
SkipToken,
|
|
9
10
|
ThrowOnError,
|
|
10
11
|
} from '@tanstack/query-core'
|
|
11
12
|
|
|
@@ -33,7 +34,9 @@ type GetSuspenseOptions<T> =
|
|
|
33
34
|
? UseSuspenseQueryOptions<TQueryFnData>
|
|
34
35
|
: // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided
|
|
35
36
|
T extends {
|
|
36
|
-
queryFn?:
|
|
37
|
+
queryFn?:
|
|
38
|
+
| QueryFunction<infer TQueryFnData, infer TQueryKey>
|
|
39
|
+
| SkipToken
|
|
37
40
|
select?: (data: any) => infer TData
|
|
38
41
|
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
39
42
|
}
|
|
@@ -44,10 +47,9 @@ type GetSuspenseOptions<T> =
|
|
|
44
47
|
TQueryKey
|
|
45
48
|
>
|
|
46
49
|
: T extends {
|
|
47
|
-
queryFn?:
|
|
48
|
-
infer TQueryFnData,
|
|
49
|
-
|
|
50
|
-
>
|
|
50
|
+
queryFn?:
|
|
51
|
+
| QueryFunction<infer TQueryFnData, infer TQueryKey>
|
|
52
|
+
| SkipToken
|
|
51
53
|
throwOnError?: ThrowOnError<any, infer TError, any, any>
|
|
52
54
|
}
|
|
53
55
|
? UseSuspenseQueryOptions<
|
package/src/useSuspenseQuery.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import { QueryObserver } from '@tanstack/query-core'
|
|
2
|
+
import { QueryObserver, skipToken } from '@tanstack/query-core'
|
|
3
3
|
import { useBaseQuery } from './useBaseQuery'
|
|
4
4
|
import { defaultThrowOnError } from './suspense'
|
|
5
5
|
import type { UseSuspenseQueryOptions, UseSuspenseQueryResult } from './types'
|
|
@@ -14,6 +14,12 @@ export function useSuspenseQuery<
|
|
|
14
14
|
options: UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
|
|
15
15
|
queryClient?: QueryClient,
|
|
16
16
|
): UseSuspenseQueryResult<TData, TError> {
|
|
17
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
18
|
+
if (options.queryFn === skipToken) {
|
|
19
|
+
console.error('skipToken is not allowed for useSuspenseQuery')
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
return useBaseQuery(
|
|
18
24
|
{
|
|
19
25
|
...options,
|