@tanstack/react-query 5.0.0-alpha.4 → 5.0.0-alpha.43
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/__testfixtures__/default-import.input.tsx +94 -0
- package/build/codemods/__testfixtures__/default-import.output.tsx +96 -0
- package/build/codemods/__testfixtures__/named-import.input.tsx +96 -0
- package/build/codemods/__testfixtures__/named-import.output.tsx +98 -0
- package/build/codemods/__testfixtures__/namespaced-import.input.tsx +86 -0
- package/build/codemods/__testfixtures__/namespaced-import.output.tsx +88 -0
- package/build/codemods/__testfixtures__/parameter-is-identifier.input.tsx +49 -0
- package/build/codemods/__testfixtures__/parameter-is-identifier.output.tsx +49 -0
- package/build/codemods/__testfixtures__/parameter-is-object-expression.input.tsx +128 -0
- package/build/codemods/__testfixtures__/parameter-is-object-expression.output.tsx +175 -0
- package/build/codemods/__testfixtures__/replace-import-specifier.input.tsx +10 -0
- package/build/codemods/__testfixtures__/replace-import-specifier.output.tsx +10 -0
- package/build/codemods/__testfixtures__/type-arguments.input.tsx +25 -0
- package/build/codemods/__testfixtures__/type-arguments.output.tsx +31 -0
- package/build/codemods/__tests__/key-transformation.test.js +32 -0
- package/build/codemods/__tests__/replace-import-specifier.test.js +12 -0
- package/build/codemods/remove-overloads/__testfixtures__/default-import.input.tsx +199 -0
- package/build/codemods/remove-overloads/__testfixtures__/default-import.output.tsx +484 -0
- package/build/codemods/remove-overloads/__tests__/remove-overloads.test.js +6 -0
- package/build/codemods/remove-overloads/remove-overloads.js +59 -0
- package/build/codemods/remove-overloads/transformers/filter-aware-usage-transformer.js +153 -0
- package/build/codemods/remove-overloads/transformers/query-fn-aware-usage-transformer.js +188 -0
- package/build/codemods/remove-overloads/utils/index.js +124 -0
- package/build/codemods/remove-overloads/utils/unknown-usage-error.js +26 -0
- package/build/codemods/src/utils/index.js +205 -0
- package/build/codemods/src/v4/key-transformation.js +138 -0
- package/build/codemods/src/v4/replace-import-specifier.js +25 -0
- package/build/codemods/transformers/query-cache-transformer.js +116 -0
- package/build/codemods/transformers/query-client-transformer.js +48 -0
- package/build/codemods/transformers/use-query-like-transformer.js +32 -0
- package/build/codemods/utils/replacers/key-replacer.js +164 -0
- package/build/lib/HydrationBoundary.d.ts +1 -0
- package/build/lib/HydrationBoundary.d.ts.map +1 -0
- package/build/lib/HydrationBoundary.esm.js +1 -0
- package/build/lib/HydrationBoundary.esm.js.map +1 -1
- package/build/lib/HydrationBoundary.js +1 -0
- package/build/lib/HydrationBoundary.js.map +1 -1
- package/build/lib/HydrationBoundary.mjs +1 -0
- package/build/lib/HydrationBoundary.mjs.map +1 -1
- package/build/lib/QueryClientProvider.d.ts +2 -1
- package/build/lib/QueryClientProvider.d.ts.map +1 -0
- package/build/lib/QueryClientProvider.esm.js +1 -0
- package/build/lib/QueryClientProvider.esm.js.map +1 -1
- package/build/lib/QueryClientProvider.js +1 -0
- package/build/lib/QueryClientProvider.js.map +1 -1
- package/build/lib/QueryClientProvider.mjs +1 -0
- package/build/lib/QueryClientProvider.mjs.map +1 -1
- package/build/lib/QueryErrorResetBoundary.d.ts +2 -1
- package/build/lib/QueryErrorResetBoundary.d.ts.map +1 -0
- package/build/lib/QueryErrorResetBoundary.esm.js +1 -0
- package/build/lib/QueryErrorResetBoundary.esm.js.map +1 -1
- package/build/lib/QueryErrorResetBoundary.js +1 -0
- package/build/lib/QueryErrorResetBoundary.js.map +1 -1
- package/build/lib/QueryErrorResetBoundary.mjs +1 -0
- package/build/lib/QueryErrorResetBoundary.mjs.map +1 -1
- package/build/lib/__tests__/HydrationBoundary.test.d.ts +1 -0
- package/build/lib/__tests__/HydrationBoundary.test.d.ts.map +1 -0
- package/build/lib/__tests__/QueryClientProvider.test.d.ts +1 -0
- package/build/lib/__tests__/QueryClientProvider.test.d.ts.map +1 -0
- package/build/lib/__tests__/QueryResetErrorBoundary.test.d.ts +1 -0
- package/build/lib/__tests__/QueryResetErrorBoundary.test.d.ts.map +1 -0
- package/build/lib/__tests__/ssr-hydration.test.d.ts +1 -0
- package/build/lib/__tests__/ssr-hydration.test.d.ts.map +1 -0
- package/build/lib/__tests__/ssr.test.d.ts +1 -3
- package/build/lib/__tests__/ssr.test.d.ts.map +1 -0
- package/build/lib/__tests__/suspense.test.d.ts +1 -0
- package/build/lib/__tests__/suspense.test.d.ts.map +1 -0
- package/build/lib/__tests__/useInfiniteQuery.test.d.ts +1 -0
- package/build/lib/__tests__/useInfiniteQuery.test.d.ts.map +1 -0
- package/build/lib/__tests__/useInfiniteQuery.type.test.d.ts +1 -0
- package/build/lib/__tests__/useInfiniteQuery.type.test.d.ts.map +1 -0
- package/build/lib/__tests__/useIsFetching.test.d.ts +1 -0
- package/build/lib/__tests__/useIsFetching.test.d.ts.map +1 -0
- package/build/lib/__tests__/useMutation.test.d.ts +1 -0
- package/build/lib/__tests__/useMutation.test.d.ts.map +1 -0
- package/build/lib/__tests__/useMutationState.test.d.ts +1 -0
- package/build/lib/__tests__/useMutationState.test.d.ts.map +1 -0
- package/build/lib/__tests__/useQueries.test.d.ts +1 -0
- package/build/lib/__tests__/useQueries.test.d.ts.map +1 -0
- package/build/lib/__tests__/useQuery.test.d.ts +1 -0
- package/build/lib/__tests__/useQuery.test.d.ts.map +1 -0
- package/build/lib/__tests__/useQuery.types.test.d.ts +1 -0
- package/build/lib/__tests__/useQuery.types.test.d.ts.map +1 -0
- package/build/lib/__tests__/utils.d.ts +6 -6
- package/build/lib/__tests__/utils.d.ts.map +1 -0
- package/build/lib/errorBoundaryUtils.d.ts +4 -3
- package/build/lib/errorBoundaryUtils.d.ts.map +1 -0
- package/build/lib/errorBoundaryUtils.esm.js +4 -3
- package/build/lib/errorBoundaryUtils.esm.js.map +1 -1
- package/build/lib/errorBoundaryUtils.js +4 -3
- package/build/lib/errorBoundaryUtils.js.map +1 -1
- package/build/lib/errorBoundaryUtils.mjs +4 -3
- package/build/lib/errorBoundaryUtils.mjs.map +1 -1
- package/build/lib/index.d.ts +2 -1
- package/build/lib/index.d.ts.map +1 -0
- package/build/lib/index.esm.js +1 -1
- package/build/lib/index.js +1 -0
- package/build/lib/index.js.map +1 -1
- package/build/lib/index.mjs +1 -1
- package/build/lib/isRestoring.d.ts +1 -0
- package/build/lib/isRestoring.d.ts.map +1 -0
- package/build/lib/isRestoring.esm.js +1 -0
- package/build/lib/isRestoring.esm.js.map +1 -1
- package/build/lib/isRestoring.js +1 -0
- package/build/lib/isRestoring.js.map +1 -1
- package/build/lib/isRestoring.mjs +1 -0
- package/build/lib/isRestoring.mjs.map +1 -1
- package/build/lib/suspense.d.ts +3 -5
- package/build/lib/suspense.d.ts.map +1 -0
- package/build/lib/suspense.esm.js +2 -9
- package/build/lib/suspense.esm.js.map +1 -1
- package/build/lib/suspense.js +2 -9
- package/build/lib/suspense.js.map +1 -1
- package/build/lib/suspense.mjs +1 -8
- package/build/lib/suspense.mjs.map +1 -1
- package/build/lib/types.d.ts +11 -10
- package/build/lib/types.d.ts.map +1 -0
- package/build/lib/useBaseQuery.d.ts +1 -0
- package/build/lib/useBaseQuery.d.ts.map +1 -0
- package/build/lib/useBaseQuery.esm.js +2 -12
- package/build/lib/useBaseQuery.esm.js.map +1 -1
- package/build/lib/useBaseQuery.js +2 -12
- package/build/lib/useBaseQuery.js.map +1 -1
- package/build/lib/useBaseQuery.mjs +2 -12
- package/build/lib/useBaseQuery.mjs.map +1 -1
- package/build/lib/useInfiniteQuery.d.ts +1 -0
- package/build/lib/useInfiniteQuery.d.ts.map +1 -0
- package/build/lib/useInfiniteQuery.esm.js +1 -0
- package/build/lib/useInfiniteQuery.esm.js.map +1 -1
- package/build/lib/useInfiniteQuery.js +1 -0
- package/build/lib/useInfiniteQuery.js.map +1 -1
- package/build/lib/useInfiniteQuery.mjs +1 -0
- package/build/lib/useInfiniteQuery.mjs.map +1 -1
- package/build/lib/useIsFetching.d.ts +1 -0
- package/build/lib/useIsFetching.d.ts.map +1 -0
- package/build/lib/useIsFetching.esm.js +1 -0
- package/build/lib/useIsFetching.esm.js.map +1 -1
- package/build/lib/useIsFetching.js +1 -0
- package/build/lib/useIsFetching.js.map +1 -1
- package/build/lib/useIsFetching.mjs +1 -0
- package/build/lib/useIsFetching.mjs.map +1 -1
- package/build/lib/useMutation.d.ts +1 -0
- package/build/lib/useMutation.d.ts.map +1 -0
- package/build/lib/useMutation.esm.js +2 -1
- package/build/lib/useMutation.esm.js.map +1 -1
- package/build/lib/useMutation.js +2 -1
- package/build/lib/useMutation.js.map +1 -1
- package/build/lib/useMutation.mjs +2 -1
- package/build/lib/useMutation.mjs.map +1 -1
- package/build/lib/useMutationState.d.ts +4 -3
- package/build/lib/useMutationState.d.ts.map +1 -0
- package/build/lib/useMutationState.esm.js +1 -0
- package/build/lib/useMutationState.esm.js.map +1 -1
- package/build/lib/useMutationState.js +1 -0
- package/build/lib/useMutationState.js.map +1 -1
- package/build/lib/useMutationState.mjs +1 -0
- package/build/lib/useMutationState.mjs.map +1 -1
- package/build/lib/useQueries.d.ts +10 -8
- package/build/lib/useQueries.d.ts.map +1 -0
- package/build/lib/useQueries.esm.js +39 -27
- package/build/lib/useQueries.esm.js.map +1 -1
- package/build/lib/useQueries.js +39 -27
- package/build/lib/useQueries.js.map +1 -1
- package/build/lib/useQueries.mjs +31 -22
- package/build/lib/useQueries.mjs.map +1 -1
- package/build/lib/useQuery.d.ts +5 -2
- package/build/lib/useQuery.d.ts.map +1 -0
- package/build/lib/useQuery.esm.js +6 -1
- package/build/lib/useQuery.esm.js.map +1 -1
- package/build/lib/useQuery.js +6 -0
- package/build/lib/useQuery.js.map +1 -1
- package/build/lib/useQuery.mjs +6 -1
- package/build/lib/useQuery.mjs.map +1 -1
- package/build/lib/utils.d.ts +1 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.esm.js.map +1 -1
- package/build/lib/utils.js.map +1 -1
- package/build/lib/utils.mjs.map +1 -1
- package/build/umd/index.development.js +191 -187
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +13 -6
- package/src/__tests__/HydrationBoundary.test.tsx +4 -3
- package/src/__tests__/QueryClientProvider.test.tsx +2 -1
- package/src/__tests__/QueryResetErrorBoundary.test.tsx +753 -620
- package/src/__tests__/ssr-hydration.test.tsx +11 -10
- package/src/__tests__/ssr.test.tsx +4 -7
- package/src/__tests__/suspense.test.tsx +17 -98
- package/src/__tests__/useInfiniteQuery.test.tsx +18 -16
- package/src/__tests__/useInfiniteQuery.type.test.tsx +94 -13
- package/src/__tests__/useMutation.test.tsx +25 -24
- package/src/__tests__/useMutationState.test.tsx +24 -58
- package/src/__tests__/useQueries.test.tsx +217 -154
- package/src/__tests__/useQuery.test.tsx +234 -365
- package/src/__tests__/useQuery.types.test.tsx +21 -1
- package/src/__tests__/utils.tsx +3 -2
- package/src/errorBoundaryUtils.ts +6 -5
- package/src/index.ts +1 -1
- package/src/suspense.ts +9 -15
- package/src/useBaseQuery.ts +2 -20
- package/src/useInfiniteQuery.ts +1 -0
- package/src/useIsFetching.ts +1 -0
- package/src/useMutation.ts +2 -1
- package/src/useMutationState.ts +4 -3
- package/src/useQueries.ts +44 -26
- package/src/useQuery.ts +23 -0
|
@@ -4,12 +4,12 @@ import { useIsMutating, useMutationState } from '../useMutationState'
|
|
|
4
4
|
import { useMutation } from '../useMutation'
|
|
5
5
|
import {
|
|
6
6
|
createQueryClient,
|
|
7
|
+
doNotExecute,
|
|
7
8
|
renderWithClient,
|
|
8
9
|
setActTimeout,
|
|
9
10
|
sleep,
|
|
10
11
|
} from './utils'
|
|
11
|
-
import
|
|
12
|
-
import { screen } from 'solid-testing-library'
|
|
12
|
+
import type { MutationState, MutationStatus } from '@tanstack/query-core'
|
|
13
13
|
|
|
14
14
|
describe('useIsMutating', () => {
|
|
15
15
|
it('should return the number of fetching mutations', async () => {
|
|
@@ -140,61 +140,6 @@ describe('useIsMutating', () => {
|
|
|
140
140
|
await waitFor(() => expect(isMutatings).toEqual([0, 1, 0]))
|
|
141
141
|
})
|
|
142
142
|
|
|
143
|
-
it('should not change state if unmounted', async () => {
|
|
144
|
-
// We have to mock the MutationCache to not unsubscribe
|
|
145
|
-
// the listener when the component is unmounted
|
|
146
|
-
class MutationCacheMock extends MutationCacheModule.MutationCache {
|
|
147
|
-
subscribe(listener: any) {
|
|
148
|
-
super.subscribe(listener)
|
|
149
|
-
return () => void 0
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const MutationCacheSpy = jest
|
|
154
|
-
.spyOn(MutationCacheModule, 'MutationCache')
|
|
155
|
-
.mockImplementation((fn) => {
|
|
156
|
-
return new MutationCacheMock(fn)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
const queryClient = createQueryClient()
|
|
160
|
-
|
|
161
|
-
function IsMutating() {
|
|
162
|
-
useIsMutating()
|
|
163
|
-
return null
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function Page() {
|
|
167
|
-
const [mounted, setMounted] = React.useState(true)
|
|
168
|
-
const { mutate: mutate1 } = useMutation({
|
|
169
|
-
mutationKey: ['mutation1'],
|
|
170
|
-
mutationFn: async () => {
|
|
171
|
-
await sleep(10)
|
|
172
|
-
return 'data'
|
|
173
|
-
},
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
React.useEffect(() => {
|
|
177
|
-
mutate1()
|
|
178
|
-
}, [mutate1])
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<div>
|
|
182
|
-
<button onClick={() => setMounted(false)}>unmount</button>
|
|
183
|
-
{mounted && <IsMutating />}
|
|
184
|
-
</div>
|
|
185
|
-
)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const { getByText } = renderWithClient(queryClient, <Page />)
|
|
189
|
-
fireEvent.click(getByText('unmount'))
|
|
190
|
-
|
|
191
|
-
// Should not display the console error
|
|
192
|
-
// "Warning: Can't perform a React state update on an unmounted component"
|
|
193
|
-
|
|
194
|
-
await sleep(20)
|
|
195
|
-
MutationCacheSpy.mockRestore()
|
|
196
|
-
})
|
|
197
|
-
|
|
198
143
|
it('should use provided custom queryClient', async () => {
|
|
199
144
|
const queryClient = createQueryClient()
|
|
200
145
|
|
|
@@ -229,6 +174,27 @@ describe('useIsMutating', () => {
|
|
|
229
174
|
})
|
|
230
175
|
|
|
231
176
|
describe('useMutationState', () => {
|
|
177
|
+
describe('types', () => {
|
|
178
|
+
it('should default to QueryState', () => {
|
|
179
|
+
doNotExecute(() => {
|
|
180
|
+
const result = useMutationState({
|
|
181
|
+
filters: { status: 'pending' },
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
expectTypeOf(result).toEqualTypeOf<Array<MutationState>>()
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
it('should infer with select', () => {
|
|
188
|
+
doNotExecute(() => {
|
|
189
|
+
const result = useMutationState({
|
|
190
|
+
filters: { status: 'pending' },
|
|
191
|
+
select: (mutation) => mutation.state.status,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
expectTypeOf(result).toEqualTypeOf<Array<MutationStatus>>()
|
|
195
|
+
})
|
|
196
|
+
})
|
|
197
|
+
})
|
|
232
198
|
it('should return variables after calling mutate', async () => {
|
|
233
199
|
const queryClient = createQueryClient()
|
|
234
200
|
const variables: unknown[][] = []
|
|
@@ -275,7 +241,7 @@ describe('useMutationState', () => {
|
|
|
275
241
|
|
|
276
242
|
await waitFor(() => rendered.getByText('data: null'))
|
|
277
243
|
|
|
278
|
-
fireEvent.click(
|
|
244
|
+
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
|
|
279
245
|
|
|
280
246
|
await waitFor(() => rendered.getByText('data: data1'))
|
|
281
247
|
|
|
@@ -2,8 +2,16 @@ import { fireEvent, render, waitFor } from '@testing-library/react'
|
|
|
2
2
|
import * as React from 'react'
|
|
3
3
|
import { ErrorBoundary } from 'react-error-boundary'
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
import type { QueryFunctionContext } from '@tanstack/query-core'
|
|
6
|
+
import { vi } from 'vitest'
|
|
7
|
+
import type {
|
|
8
|
+
QueryFunction,
|
|
9
|
+
QueryKey,
|
|
10
|
+
QueryObserverResult,
|
|
11
|
+
UseQueryOptions,
|
|
12
|
+
UseQueryResult,
|
|
13
|
+
} from '..'
|
|
14
|
+
import { QueryCache, useQueries } from '..'
|
|
7
15
|
import {
|
|
8
16
|
createQueryClient,
|
|
9
17
|
expectType,
|
|
@@ -12,15 +20,6 @@ import {
|
|
|
12
20
|
renderWithClient,
|
|
13
21
|
sleep,
|
|
14
22
|
} from './utils'
|
|
15
|
-
import type {
|
|
16
|
-
QueryFunction,
|
|
17
|
-
QueryKey,
|
|
18
|
-
QueryObserverResult,
|
|
19
|
-
UseQueryOptions,
|
|
20
|
-
UseQueryResult,
|
|
21
|
-
} from '..'
|
|
22
|
-
import { QueriesObserver, QueryCache, useQueries } from '..'
|
|
23
|
-
import type { QueryFunctionContext } from '@tanstack/query-core'
|
|
24
23
|
|
|
25
24
|
describe('useQueries', () => {
|
|
26
25
|
const queryCache = new QueryCache()
|
|
@@ -72,6 +71,52 @@ describe('useQueries', () => {
|
|
|
72
71
|
expect(results[2]).toMatchObject([{ data: 1 }, { data: 2 }])
|
|
73
72
|
})
|
|
74
73
|
|
|
74
|
+
it('should track results', async () => {
|
|
75
|
+
const key1 = queryKey()
|
|
76
|
+
const results: UseQueryResult[][] = []
|
|
77
|
+
let count = 0
|
|
78
|
+
|
|
79
|
+
function Page() {
|
|
80
|
+
const result = useQueries({
|
|
81
|
+
queries: [
|
|
82
|
+
{
|
|
83
|
+
queryKey: key1,
|
|
84
|
+
queryFn: async () => {
|
|
85
|
+
await sleep(10)
|
|
86
|
+
count++
|
|
87
|
+
return count
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
})
|
|
92
|
+
results.push(result)
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div>
|
|
96
|
+
<div>data: {String(result[0].data ?? 'null')} </div>
|
|
97
|
+
<button onClick={() => result[0].refetch()}>refetch</button>
|
|
98
|
+
</div>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const rendered = renderWithClient(queryClient, <Page />)
|
|
103
|
+
|
|
104
|
+
await waitFor(() => rendered.getByText('data: 1'))
|
|
105
|
+
|
|
106
|
+
expect(results.length).toBe(2)
|
|
107
|
+
expect(results[0]).toMatchObject([{ data: undefined }])
|
|
108
|
+
expect(results[1]).toMatchObject([{ data: 1 }])
|
|
109
|
+
|
|
110
|
+
fireEvent.click(rendered.getByRole('button', { name: /refetch/i }))
|
|
111
|
+
|
|
112
|
+
await waitFor(() => rendered.getByText('data: 2'))
|
|
113
|
+
|
|
114
|
+
// only one render for data update, no render for isFetching transition
|
|
115
|
+
expect(results.length).toBe(3)
|
|
116
|
+
|
|
117
|
+
expect(results[2]).toMatchObject([{ data: 2 }])
|
|
118
|
+
})
|
|
119
|
+
|
|
75
120
|
it('handles type parameter - tuple of tuples', async () => {
|
|
76
121
|
const key1 = queryKey()
|
|
77
122
|
const key2 = queryKey()
|
|
@@ -145,10 +190,6 @@ describe('useQueries', () => {
|
|
|
145
190
|
expectTypeNotAny(a)
|
|
146
191
|
return a.toLowerCase()
|
|
147
192
|
},
|
|
148
|
-
onSuccess: (a) => {
|
|
149
|
-
expectType<string>(a)
|
|
150
|
-
expectTypeNotAny(a)
|
|
151
|
-
},
|
|
152
193
|
placeholderData: 'string',
|
|
153
194
|
// @ts-expect-error (initialData: string)
|
|
154
195
|
initialData: 123,
|
|
@@ -161,14 +202,6 @@ describe('useQueries', () => {
|
|
|
161
202
|
expectTypeNotAny(a)
|
|
162
203
|
return parseInt(a)
|
|
163
204
|
},
|
|
164
|
-
onSuccess: (a) => {
|
|
165
|
-
expectType<number>(a)
|
|
166
|
-
expectTypeNotAny(a)
|
|
167
|
-
},
|
|
168
|
-
onError: (e) => {
|
|
169
|
-
expectType<boolean>(e)
|
|
170
|
-
expectTypeNotAny(e)
|
|
171
|
-
},
|
|
172
205
|
placeholderData: 'string',
|
|
173
206
|
// @ts-expect-error (initialData: string)
|
|
174
207
|
initialData: 123,
|
|
@@ -305,10 +338,6 @@ describe('useQueries', () => {
|
|
|
305
338
|
expectTypeNotAny(a)
|
|
306
339
|
return a.toLowerCase()
|
|
307
340
|
},
|
|
308
|
-
onSuccess: (a) => {
|
|
309
|
-
expectType<string>(a)
|
|
310
|
-
expectTypeNotAny(a)
|
|
311
|
-
},
|
|
312
341
|
placeholderData: 'string',
|
|
313
342
|
// @ts-expect-error (initialData: string)
|
|
314
343
|
initialData: 123,
|
|
@@ -321,14 +350,6 @@ describe('useQueries', () => {
|
|
|
321
350
|
expectTypeNotAny(a)
|
|
322
351
|
return parseInt(a)
|
|
323
352
|
},
|
|
324
|
-
onSuccess: (a) => {
|
|
325
|
-
expectType<number>(a)
|
|
326
|
-
expectTypeNotAny(a)
|
|
327
|
-
},
|
|
328
|
-
onError: (e) => {
|
|
329
|
-
expectType<boolean>(e)
|
|
330
|
-
expectTypeNotAny(e)
|
|
331
|
-
},
|
|
332
353
|
placeholderData: 'string',
|
|
333
354
|
// @ts-expect-error (initialData: string)
|
|
334
355
|
initialData: 123,
|
|
@@ -424,60 +445,38 @@ describe('useQueries', () => {
|
|
|
424
445
|
],
|
|
425
446
|
})
|
|
426
447
|
|
|
427
|
-
// select
|
|
448
|
+
// select params are "indirectly" enforced
|
|
428
449
|
useQueries({
|
|
429
450
|
queries: [
|
|
430
451
|
// unfortunately TS will not suggest the type for you
|
|
431
452
|
{
|
|
432
453
|
queryKey: key1,
|
|
433
454
|
queryFn: () => 'string',
|
|
434
|
-
// @ts-expect-error (noImplicitAny)
|
|
435
|
-
onSuccess: (a) => null,
|
|
436
|
-
// @ts-expect-error (noImplicitAny)
|
|
437
|
-
onSettled: (a) => null,
|
|
438
455
|
},
|
|
439
456
|
// however you can add a type to the callback
|
|
440
457
|
{
|
|
441
458
|
queryKey: key2,
|
|
442
459
|
queryFn: () => 'string',
|
|
443
|
-
onSuccess: (a: string) => {
|
|
444
|
-
expectType<string>(a)
|
|
445
|
-
expectTypeNotAny(a)
|
|
446
|
-
},
|
|
447
|
-
onSettled: (a: string | undefined) => {
|
|
448
|
-
expectType<string | undefined>(a)
|
|
449
|
-
expectTypeNotAny(a)
|
|
450
|
-
},
|
|
451
460
|
},
|
|
452
461
|
// the type you do pass is enforced
|
|
453
462
|
{
|
|
454
463
|
queryKey: key3,
|
|
455
464
|
queryFn: () => 'string',
|
|
456
|
-
// @ts-expect-error (only accepts string)
|
|
457
|
-
onSuccess: (a: number) => null,
|
|
458
465
|
},
|
|
459
466
|
{
|
|
460
467
|
queryKey: key4,
|
|
461
468
|
queryFn: () => 'string',
|
|
462
469
|
select: (a: string) => parseInt(a),
|
|
463
|
-
// @ts-expect-error (select is defined => only accepts number)
|
|
464
|
-
onSuccess: (a: string) => null,
|
|
465
|
-
onSettled: (a: number | undefined) => {
|
|
466
|
-
expectType<number | undefined>(a)
|
|
467
|
-
expectTypeNotAny(a)
|
|
468
|
-
},
|
|
469
470
|
},
|
|
470
471
|
],
|
|
471
472
|
})
|
|
472
473
|
|
|
473
474
|
// callbacks are also indirectly enforced with Array.map
|
|
474
475
|
useQueries({
|
|
475
|
-
// @ts-expect-error (onSuccess only accepts string)
|
|
476
476
|
queries: Array(50).map((_, i) => ({
|
|
477
477
|
queryKey: ['key', i] as const,
|
|
478
478
|
queryFn: () => i + 10,
|
|
479
479
|
select: (data: number) => data.toString(),
|
|
480
|
-
onSuccess: (_data: number) => null,
|
|
481
480
|
})),
|
|
482
481
|
})
|
|
483
482
|
useQueries({
|
|
@@ -485,7 +484,6 @@ describe('useQueries', () => {
|
|
|
485
484
|
queryKey: ['key', i] as const,
|
|
486
485
|
queryFn: () => i + 10,
|
|
487
486
|
select: (data: number) => data.toString(),
|
|
488
|
-
onSuccess: (_data: string) => null,
|
|
489
487
|
})),
|
|
490
488
|
})
|
|
491
489
|
|
|
@@ -495,32 +493,15 @@ describe('useQueries', () => {
|
|
|
495
493
|
{
|
|
496
494
|
queryKey: key1,
|
|
497
495
|
queryFn: () => 'string',
|
|
498
|
-
// @ts-expect-error (noImplicitAny)
|
|
499
|
-
onSuccess: (a) => null,
|
|
500
|
-
// @ts-expect-error (noImplicitAny)
|
|
501
|
-
onSettled: (a) => null,
|
|
502
496
|
},
|
|
503
497
|
{
|
|
504
498
|
queryKey: key2,
|
|
505
499
|
queryFn: () => 'string',
|
|
506
|
-
onSuccess: (a: string) => {
|
|
507
|
-
expectType<string>(a)
|
|
508
|
-
expectTypeNotAny(a)
|
|
509
|
-
},
|
|
510
|
-
onSettled: (a: string | undefined) => {
|
|
511
|
-
expectType<string | undefined>(a)
|
|
512
|
-
expectTypeNotAny(a)
|
|
513
|
-
},
|
|
514
500
|
},
|
|
515
501
|
{
|
|
516
502
|
queryKey: key4,
|
|
517
503
|
queryFn: () => 'string',
|
|
518
504
|
select: (a: string) => parseInt(a),
|
|
519
|
-
onSuccess: (_a: number) => null,
|
|
520
|
-
onSettled: (a: number | undefined) => {
|
|
521
|
-
expectType<number | undefined>(a)
|
|
522
|
-
expectTypeNotAny(a)
|
|
523
|
-
},
|
|
524
505
|
},
|
|
525
506
|
],
|
|
526
507
|
})
|
|
@@ -534,12 +515,6 @@ describe('useQueries', () => {
|
|
|
534
515
|
{
|
|
535
516
|
queryKey: key1,
|
|
536
517
|
queryFn: () => Promise.resolve('string'),
|
|
537
|
-
onSuccess: (a: string) => {
|
|
538
|
-
expectType<string>(a)
|
|
539
|
-
expectTypeNotAny(a)
|
|
540
|
-
},
|
|
541
|
-
// @ts-expect-error (refuses to accept a Promise)
|
|
542
|
-
onSettled: (a: Promise<string>) => null,
|
|
543
518
|
},
|
|
544
519
|
],
|
|
545
520
|
})
|
|
@@ -646,11 +621,10 @@ describe('useQueries', () => {
|
|
|
646
621
|
queries: queries.map(
|
|
647
622
|
// no need to type the mapped query
|
|
648
623
|
(query) => {
|
|
649
|
-
const { queryFn: fn, queryKey: key
|
|
624
|
+
const { queryFn: fn, queryKey: key } = query
|
|
650
625
|
expectType<QueryFunction<TQueryFnData, TQueryKey> | undefined>(fn)
|
|
651
626
|
return {
|
|
652
627
|
queryKey: key,
|
|
653
|
-
onError: err,
|
|
654
628
|
queryFn: fn
|
|
655
629
|
? (ctx: QueryFunctionContext<TQueryKey>) => {
|
|
656
630
|
expectType<TQueryKey>(ctx.queryKey)
|
|
@@ -716,67 +690,8 @@ describe('useQueries', () => {
|
|
|
716
690
|
}
|
|
717
691
|
})
|
|
718
692
|
|
|
719
|
-
it(
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
// We have to mock the QueriesObserver to not unsubscribe
|
|
723
|
-
// the listener when the component is unmounted
|
|
724
|
-
class QueriesObserverMock extends QueriesObserver {
|
|
725
|
-
subscribe(listener: any) {
|
|
726
|
-
super.subscribe(listener)
|
|
727
|
-
return () => void 0
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
const QueriesObserverSpy = jest
|
|
732
|
-
.spyOn(QueriesObserverModule, 'QueriesObserver')
|
|
733
|
-
.mockImplementation((fn) => {
|
|
734
|
-
return new QueriesObserverMock(fn)
|
|
735
|
-
})
|
|
736
|
-
|
|
737
|
-
function Queries() {
|
|
738
|
-
useQueries({
|
|
739
|
-
queries: [
|
|
740
|
-
{
|
|
741
|
-
queryKey: key1,
|
|
742
|
-
queryFn: async () => {
|
|
743
|
-
await sleep(10)
|
|
744
|
-
return 1
|
|
745
|
-
},
|
|
746
|
-
},
|
|
747
|
-
],
|
|
748
|
-
})
|
|
749
|
-
|
|
750
|
-
return (
|
|
751
|
-
<div>
|
|
752
|
-
<span>queries</span>
|
|
753
|
-
</div>
|
|
754
|
-
)
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
function Page() {
|
|
758
|
-
const [mounted, setMounted] = React.useState(true)
|
|
759
|
-
|
|
760
|
-
return (
|
|
761
|
-
<div>
|
|
762
|
-
<button onClick={() => setMounted(false)}>unmount</button>
|
|
763
|
-
{mounted && <Queries />}
|
|
764
|
-
</div>
|
|
765
|
-
)
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
const { getByText } = renderWithClient(queryClient, <Page />)
|
|
769
|
-
fireEvent.click(getByText('unmount'))
|
|
770
|
-
|
|
771
|
-
// Should not display the console error
|
|
772
|
-
// "Warning: Can't perform a React state update on an unmounted component"
|
|
773
|
-
|
|
774
|
-
await sleep(20)
|
|
775
|
-
QueriesObserverSpy.mockRestore()
|
|
776
|
-
})
|
|
777
|
-
|
|
778
|
-
it("should throw error if in one of queries' queryFn throws and throwErrors is in use", async () => {
|
|
779
|
-
const consoleMock = jest
|
|
693
|
+
it("should throw error if in one of queries' queryFn throws and throwOnError is in use", async () => {
|
|
694
|
+
const consoleMock = vi
|
|
780
695
|
.spyOn(console, 'error')
|
|
781
696
|
.mockImplementation(() => undefined)
|
|
782
697
|
const key1 = queryKey()
|
|
@@ -792,14 +707,14 @@ describe('useQueries', () => {
|
|
|
792
707
|
queryFn: () =>
|
|
793
708
|
Promise.reject(
|
|
794
709
|
new Error(
|
|
795
|
-
'this should not throw because
|
|
710
|
+
'this should not throw because throwOnError is not set',
|
|
796
711
|
),
|
|
797
712
|
),
|
|
798
713
|
},
|
|
799
714
|
{
|
|
800
715
|
queryKey: key2,
|
|
801
716
|
queryFn: () => Promise.reject(new Error('single query error')),
|
|
802
|
-
|
|
717
|
+
throwOnError: true,
|
|
803
718
|
retry: false,
|
|
804
719
|
},
|
|
805
720
|
{
|
|
@@ -812,7 +727,7 @@ describe('useQueries', () => {
|
|
|
812
727
|
Promise.reject(
|
|
813
728
|
new Error('this should not throw because query#2 already did'),
|
|
814
729
|
),
|
|
815
|
-
|
|
730
|
+
throwOnError: true,
|
|
816
731
|
retry: false,
|
|
817
732
|
},
|
|
818
733
|
],
|
|
@@ -840,8 +755,8 @@ describe('useQueries', () => {
|
|
|
840
755
|
consoleMock.mockRestore()
|
|
841
756
|
})
|
|
842
757
|
|
|
843
|
-
it("should throw error if in one of queries' queryFn throws and
|
|
844
|
-
const consoleMock =
|
|
758
|
+
it("should throw error if in one of queries' queryFn throws and throwOnError function resolves to true", async () => {
|
|
759
|
+
const consoleMock = vi
|
|
845
760
|
.spyOn(console, 'error')
|
|
846
761
|
.mockImplementation(() => undefined)
|
|
847
762
|
const key1 = queryKey()
|
|
@@ -857,10 +772,10 @@ describe('useQueries', () => {
|
|
|
857
772
|
queryFn: () =>
|
|
858
773
|
Promise.reject(
|
|
859
774
|
new Error(
|
|
860
|
-
'this should not throw because
|
|
775
|
+
'this should not throw because throwOnError function resolves to false',
|
|
861
776
|
),
|
|
862
777
|
),
|
|
863
|
-
|
|
778
|
+
throwOnError: () => false,
|
|
864
779
|
retry: false,
|
|
865
780
|
},
|
|
866
781
|
{
|
|
@@ -870,7 +785,7 @@ describe('useQueries', () => {
|
|
|
870
785
|
{
|
|
871
786
|
queryKey: key3,
|
|
872
787
|
queryFn: () => Promise.reject(new Error('single query error')),
|
|
873
|
-
|
|
788
|
+
throwOnError: () => true,
|
|
874
789
|
retry: false,
|
|
875
790
|
},
|
|
876
791
|
{
|
|
@@ -879,7 +794,7 @@ describe('useQueries', () => {
|
|
|
879
794
|
Promise.reject(
|
|
880
795
|
new Error('this should not throw because query#3 already did'),
|
|
881
796
|
),
|
|
882
|
-
|
|
797
|
+
throwOnError: true,
|
|
883
798
|
retry: false,
|
|
884
799
|
},
|
|
885
800
|
],
|
|
@@ -933,4 +848,152 @@ describe('useQueries', () => {
|
|
|
933
848
|
|
|
934
849
|
await waitFor(() => rendered.getByText('data: custom client'))
|
|
935
850
|
})
|
|
851
|
+
|
|
852
|
+
it('should combine queries', async () => {
|
|
853
|
+
const key1 = queryKey()
|
|
854
|
+
const key2 = queryKey()
|
|
855
|
+
|
|
856
|
+
function Page() {
|
|
857
|
+
const queries = useQueries(
|
|
858
|
+
{
|
|
859
|
+
queries: [
|
|
860
|
+
{
|
|
861
|
+
queryKey: key1,
|
|
862
|
+
queryFn: () => Promise.resolve('first result'),
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
queryKey: key2,
|
|
866
|
+
queryFn: () => Promise.resolve('second result'),
|
|
867
|
+
},
|
|
868
|
+
],
|
|
869
|
+
combine: (results) => {
|
|
870
|
+
return {
|
|
871
|
+
combined: true,
|
|
872
|
+
res: results.map((res) => res.data).join(','),
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
},
|
|
876
|
+
queryClient,
|
|
877
|
+
)
|
|
878
|
+
|
|
879
|
+
return (
|
|
880
|
+
<div>
|
|
881
|
+
<div>
|
|
882
|
+
data: {String(queries.combined)} {queries.res}
|
|
883
|
+
</div>
|
|
884
|
+
</div>
|
|
885
|
+
)
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
const rendered = render(<Page />)
|
|
889
|
+
|
|
890
|
+
await waitFor(() =>
|
|
891
|
+
rendered.getByText('data: true first result,second result'),
|
|
892
|
+
)
|
|
893
|
+
})
|
|
894
|
+
|
|
895
|
+
it('should track property access through combine function', async () => {
|
|
896
|
+
const key1 = queryKey()
|
|
897
|
+
const key2 = queryKey()
|
|
898
|
+
let count = 0
|
|
899
|
+
const results: Array<unknown> = []
|
|
900
|
+
|
|
901
|
+
function Page() {
|
|
902
|
+
const queries = useQueries(
|
|
903
|
+
{
|
|
904
|
+
queries: [
|
|
905
|
+
{
|
|
906
|
+
queryKey: key1,
|
|
907
|
+
queryFn: async () => {
|
|
908
|
+
await sleep(10)
|
|
909
|
+
return Promise.resolve('first result ' + count)
|
|
910
|
+
},
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
queryKey: key2,
|
|
914
|
+
queryFn: async () => {
|
|
915
|
+
await sleep(20)
|
|
916
|
+
return Promise.resolve('second result ' + count)
|
|
917
|
+
},
|
|
918
|
+
},
|
|
919
|
+
],
|
|
920
|
+
combine: (queryResults) => {
|
|
921
|
+
return {
|
|
922
|
+
combined: true,
|
|
923
|
+
refetch: () => queryResults.forEach((res) => res.refetch()),
|
|
924
|
+
res: queryResults
|
|
925
|
+
.flatMap((res) => (res.data ? [res.data] : []))
|
|
926
|
+
.join(','),
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
},
|
|
930
|
+
queryClient,
|
|
931
|
+
)
|
|
932
|
+
|
|
933
|
+
results.push(queries)
|
|
934
|
+
|
|
935
|
+
return (
|
|
936
|
+
<div>
|
|
937
|
+
<div>
|
|
938
|
+
data: {String(queries.combined)} {queries.res}
|
|
939
|
+
</div>
|
|
940
|
+
<button onClick={() => queries.refetch()}>refetch</button>
|
|
941
|
+
</div>
|
|
942
|
+
)
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
const rendered = render(<Page />)
|
|
946
|
+
|
|
947
|
+
await waitFor(() =>
|
|
948
|
+
rendered.getByText('data: true first result 0,second result 0'),
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
expect(results.length).toBe(3)
|
|
952
|
+
|
|
953
|
+
expect(results[0]).toStrictEqual({
|
|
954
|
+
combined: true,
|
|
955
|
+
refetch: expect.any(Function),
|
|
956
|
+
res: '',
|
|
957
|
+
})
|
|
958
|
+
|
|
959
|
+
expect(results[1]).toStrictEqual({
|
|
960
|
+
combined: true,
|
|
961
|
+
refetch: expect.any(Function),
|
|
962
|
+
res: 'first result 0',
|
|
963
|
+
})
|
|
964
|
+
|
|
965
|
+
expect(results[2]).toStrictEqual({
|
|
966
|
+
combined: true,
|
|
967
|
+
refetch: expect.any(Function),
|
|
968
|
+
res: 'first result 0,second result 0',
|
|
969
|
+
})
|
|
970
|
+
|
|
971
|
+
count++
|
|
972
|
+
|
|
973
|
+
fireEvent.click(rendered.getByRole('button', { name: /refetch/i }))
|
|
974
|
+
|
|
975
|
+
await waitFor(() =>
|
|
976
|
+
rendered.getByText('data: true first result 1,second result 1'),
|
|
977
|
+
)
|
|
978
|
+
|
|
979
|
+
expect(results.length).toBe(5)
|
|
980
|
+
|
|
981
|
+
expect(results[3]).toStrictEqual({
|
|
982
|
+
combined: true,
|
|
983
|
+
refetch: expect.any(Function),
|
|
984
|
+
res: 'first result 1,second result 0',
|
|
985
|
+
})
|
|
986
|
+
|
|
987
|
+
expect(results[4]).toStrictEqual({
|
|
988
|
+
combined: true,
|
|
989
|
+
refetch: expect.any(Function),
|
|
990
|
+
res: 'first result 1,second result 1',
|
|
991
|
+
})
|
|
992
|
+
|
|
993
|
+
fireEvent.click(rendered.getByRole('button', { name: /refetch/i }))
|
|
994
|
+
|
|
995
|
+
await sleep(50)
|
|
996
|
+
// no further re-render because data didn't change
|
|
997
|
+
expect(results.length).toBe(5)
|
|
998
|
+
})
|
|
936
999
|
})
|