@tanstack/react-query 4.5.0 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lib/QueryErrorResetBoundary.d.ts +1 -2
- package/build/lib/QueryErrorResetBoundary.esm.js.map +1 -1
- package/build/lib/QueryErrorResetBoundary.js.map +1 -1
- package/build/lib/QueryErrorResetBoundary.mjs.map +1 -1
- package/build/lib/errorBoundaryUtils.d.ts +10 -0
- package/build/lib/errorBoundaryUtils.esm.js +27 -0
- package/build/lib/errorBoundaryUtils.esm.js.map +1 -0
- package/build/lib/errorBoundaryUtils.js +53 -0
- package/build/lib/errorBoundaryUtils.js.map +1 -0
- package/build/lib/errorBoundaryUtils.mjs +27 -0
- package/build/lib/errorBoundaryUtils.mjs.map +1 -0
- package/build/lib/useBaseQuery.esm.js +9 -12
- package/build/lib/useBaseQuery.esm.js.map +1 -1
- package/build/lib/useBaseQuery.js +9 -12
- package/build/lib/useBaseQuery.js.map +1 -1
- package/build/lib/useBaseQuery.mjs +9 -12
- package/build/lib/useBaseQuery.mjs.map +1 -1
- package/build/lib/useQueries.esm.js +22 -0
- package/build/lib/useQueries.esm.js.map +1 -1
- package/build/lib/useQueries.js +22 -0
- package/build/lib/useQueries.js.map +1 -1
- package/build/lib/useQueries.mjs +22 -0
- package/build/lib/useQueries.mjs.map +1 -1
- package/build/umd/index.development.js +88 -41
- 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 +2 -2
- package/src/QueryErrorResetBoundary.tsx +1 -1
- package/src/__tests__/useQueries.test.tsx +124 -0
- package/src/__tests__/useQuery.test.tsx +2 -0
- package/src/errorBoundaryUtils.ts +72 -0
- package/src/useBaseQuery.ts +14 -18
- package/src/useQueries.ts +27 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-query",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.1",
|
|
4
4
|
"description": "Hooks for managing, caching and syncing asynchronous and remote data in React",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"react-error-boundary": "^3.1.4"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@tanstack/query-core": "4.
|
|
50
|
+
"@tanstack/query-core": "4.6.1",
|
|
51
51
|
"use-sync-external-store": "^1.2.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
@@ -1102,4 +1102,128 @@ describe('useQueries', () => {
|
|
|
1102
1102
|
await waitFor(() => rendered.getByText('error boundary'))
|
|
1103
1103
|
})
|
|
1104
1104
|
})
|
|
1105
|
+
|
|
1106
|
+
it("should throw error if in one of queries' queryFn throws and useErrorBoundary is in use", async () => {
|
|
1107
|
+
const key1 = queryKey()
|
|
1108
|
+
const key2 = queryKey()
|
|
1109
|
+
const key3 = queryKey()
|
|
1110
|
+
const key4 = queryKey()
|
|
1111
|
+
|
|
1112
|
+
function Page() {
|
|
1113
|
+
useQueries({
|
|
1114
|
+
queries: [
|
|
1115
|
+
{
|
|
1116
|
+
queryKey: key1,
|
|
1117
|
+
queryFn: () =>
|
|
1118
|
+
Promise.reject(
|
|
1119
|
+
new Error(
|
|
1120
|
+
'this should not throw because useErrorBoundary is not set',
|
|
1121
|
+
),
|
|
1122
|
+
),
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
queryKey: key2,
|
|
1126
|
+
queryFn: () => Promise.reject(new Error('single query error')),
|
|
1127
|
+
useErrorBoundary: true,
|
|
1128
|
+
retry: false,
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
queryKey: key3,
|
|
1132
|
+
queryFn: async () => 2,
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
queryKey: key4,
|
|
1136
|
+
queryFn: async () =>
|
|
1137
|
+
Promise.reject(
|
|
1138
|
+
new Error('this should not throw because query#2 already did'),
|
|
1139
|
+
),
|
|
1140
|
+
useErrorBoundary: true,
|
|
1141
|
+
retry: false,
|
|
1142
|
+
},
|
|
1143
|
+
],
|
|
1144
|
+
})
|
|
1145
|
+
|
|
1146
|
+
return null
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
const rendered = renderWithClient(
|
|
1150
|
+
queryClient,
|
|
1151
|
+
<ErrorBoundary
|
|
1152
|
+
fallbackRender={({ error }) => (
|
|
1153
|
+
<div>
|
|
1154
|
+
<div>error boundary</div>
|
|
1155
|
+
<div>{error.message}</div>
|
|
1156
|
+
</div>
|
|
1157
|
+
)}
|
|
1158
|
+
>
|
|
1159
|
+
<Page />
|
|
1160
|
+
</ErrorBoundary>,
|
|
1161
|
+
)
|
|
1162
|
+
|
|
1163
|
+
await waitFor(() => rendered.getByText('error boundary'))
|
|
1164
|
+
await waitFor(() => rendered.getByText('single query error'))
|
|
1165
|
+
})
|
|
1166
|
+
|
|
1167
|
+
it("should throw error if in one of queries' queryFn throws and useErrorBoundary function resolves to true", async () => {
|
|
1168
|
+
const key1 = queryKey()
|
|
1169
|
+
const key2 = queryKey()
|
|
1170
|
+
const key3 = queryKey()
|
|
1171
|
+
const key4 = queryKey()
|
|
1172
|
+
|
|
1173
|
+
function Page() {
|
|
1174
|
+
useQueries({
|
|
1175
|
+
queries: [
|
|
1176
|
+
{
|
|
1177
|
+
queryKey: key1,
|
|
1178
|
+
queryFn: () =>
|
|
1179
|
+
Promise.reject(
|
|
1180
|
+
new Error(
|
|
1181
|
+
'this should not throw because useErrorBoundary function resolves to false',
|
|
1182
|
+
),
|
|
1183
|
+
),
|
|
1184
|
+
useErrorBoundary: () => false,
|
|
1185
|
+
retry: false,
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
queryKey: key2,
|
|
1189
|
+
queryFn: async () => 2,
|
|
1190
|
+
},
|
|
1191
|
+
{
|
|
1192
|
+
queryKey: key3,
|
|
1193
|
+
queryFn: () => Promise.reject(new Error('single query error')),
|
|
1194
|
+
useErrorBoundary: () => true,
|
|
1195
|
+
retry: false,
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
queryKey: key4,
|
|
1199
|
+
queryFn: async () =>
|
|
1200
|
+
Promise.reject(
|
|
1201
|
+
new Error('this should not throw because query#3 already did'),
|
|
1202
|
+
),
|
|
1203
|
+
useErrorBoundary: true,
|
|
1204
|
+
retry: false,
|
|
1205
|
+
},
|
|
1206
|
+
],
|
|
1207
|
+
})
|
|
1208
|
+
|
|
1209
|
+
return null
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
const rendered = renderWithClient(
|
|
1213
|
+
queryClient,
|
|
1214
|
+
<ErrorBoundary
|
|
1215
|
+
fallbackRender={({ error }) => (
|
|
1216
|
+
<div>
|
|
1217
|
+
<div>error boundary</div>
|
|
1218
|
+
<div>{error.message}</div>
|
|
1219
|
+
</div>
|
|
1220
|
+
)}
|
|
1221
|
+
>
|
|
1222
|
+
<Page />
|
|
1223
|
+
</ErrorBoundary>,
|
|
1224
|
+
)
|
|
1225
|
+
|
|
1226
|
+
await waitFor(() => rendered.getByText('error boundary'))
|
|
1227
|
+
await waitFor(() => rendered.getByText('single query error'))
|
|
1228
|
+
})
|
|
1105
1229
|
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DefaultedQueryObserverOptions,
|
|
3
|
+
Query,
|
|
4
|
+
QueryKey,
|
|
5
|
+
QueryObserverResult,
|
|
6
|
+
UseErrorBoundary,
|
|
7
|
+
} from '@tanstack/query-core'
|
|
8
|
+
import type { QueryErrorResetBoundaryValue } from './QueryErrorResetBoundary'
|
|
9
|
+
import * as React from 'react'
|
|
10
|
+
import { shouldThrowError } from './utils'
|
|
11
|
+
|
|
12
|
+
export const ensurePreventErrorBoundaryRetry = <
|
|
13
|
+
TQueryFnData,
|
|
14
|
+
TError,
|
|
15
|
+
TData,
|
|
16
|
+
TQueryData,
|
|
17
|
+
TQueryKey extends QueryKey,
|
|
18
|
+
>(
|
|
19
|
+
options: DefaultedQueryObserverOptions<
|
|
20
|
+
TQueryFnData,
|
|
21
|
+
TError,
|
|
22
|
+
TData,
|
|
23
|
+
TQueryData,
|
|
24
|
+
TQueryKey
|
|
25
|
+
>,
|
|
26
|
+
errorResetBoundary: QueryErrorResetBoundaryValue,
|
|
27
|
+
) => {
|
|
28
|
+
if (options.suspense || options.useErrorBoundary) {
|
|
29
|
+
// Prevent retrying failed query if the error boundary has not been reset yet
|
|
30
|
+
if (!errorResetBoundary.isReset()) {
|
|
31
|
+
options.retryOnMount = false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const useClearResetErrorBoundary = (
|
|
37
|
+
errorResetBoundary: QueryErrorResetBoundaryValue,
|
|
38
|
+
) => {
|
|
39
|
+
React.useEffect(() => {
|
|
40
|
+
errorResetBoundary.clearReset()
|
|
41
|
+
}, [errorResetBoundary])
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const getHasError = <
|
|
45
|
+
TData,
|
|
46
|
+
TError,
|
|
47
|
+
TQueryFnData,
|
|
48
|
+
TQueryData,
|
|
49
|
+
TQueryKey extends QueryKey,
|
|
50
|
+
>({
|
|
51
|
+
result,
|
|
52
|
+
errorResetBoundary,
|
|
53
|
+
useErrorBoundary,
|
|
54
|
+
query,
|
|
55
|
+
}: {
|
|
56
|
+
result: QueryObserverResult<TData, TError>
|
|
57
|
+
errorResetBoundary: QueryErrorResetBoundaryValue
|
|
58
|
+
useErrorBoundary: UseErrorBoundary<
|
|
59
|
+
TQueryFnData,
|
|
60
|
+
TError,
|
|
61
|
+
TQueryData,
|
|
62
|
+
TQueryKey
|
|
63
|
+
>
|
|
64
|
+
query: Query<TQueryFnData, TError, TQueryData, TQueryKey>
|
|
65
|
+
}) => {
|
|
66
|
+
return (
|
|
67
|
+
result.isError &&
|
|
68
|
+
!errorResetBoundary.isReset() &&
|
|
69
|
+
!result.isFetching &&
|
|
70
|
+
shouldThrowError(useErrorBoundary, [result.error, query])
|
|
71
|
+
)
|
|
72
|
+
}
|
package/src/useBaseQuery.ts
CHANGED
|
@@ -6,8 +6,12 @@ import { notifyManager } from '@tanstack/query-core'
|
|
|
6
6
|
import { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'
|
|
7
7
|
import { useQueryClient } from './QueryClientProvider'
|
|
8
8
|
import type { UseBaseQueryOptions } from './types'
|
|
9
|
-
import { shouldThrowError } from './utils'
|
|
10
9
|
import { useIsRestoring } from './isRestoring'
|
|
10
|
+
import {
|
|
11
|
+
ensurePreventErrorBoundaryRetry,
|
|
12
|
+
getHasError,
|
|
13
|
+
useClearResetErrorBoundary,
|
|
14
|
+
} from './errorBoundaryUtils'
|
|
11
15
|
|
|
12
16
|
export function useBaseQuery<
|
|
13
17
|
TQueryFnData,
|
|
@@ -62,12 +66,9 @@ export function useBaseQuery<
|
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
defaultedOptions.retryOnMount = false
|
|
69
|
-
}
|
|
70
|
-
}
|
|
69
|
+
ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)
|
|
70
|
+
|
|
71
|
+
useClearResetErrorBoundary(errorResetBoundary)
|
|
71
72
|
|
|
72
73
|
const [observer] = React.useState(
|
|
73
74
|
() =>
|
|
@@ -91,10 +92,6 @@ export function useBaseQuery<
|
|
|
91
92
|
() => observer.getCurrentResult(),
|
|
92
93
|
)
|
|
93
94
|
|
|
94
|
-
React.useEffect(() => {
|
|
95
|
-
errorResetBoundary.clearReset()
|
|
96
|
-
}, [errorResetBoundary])
|
|
97
|
-
|
|
98
95
|
React.useEffect(() => {
|
|
99
96
|
// Do not notify on updates because of changes in the options because
|
|
100
97
|
// these changes should already be reflected in the optimistic result.
|
|
@@ -123,13 +120,12 @@ export function useBaseQuery<
|
|
|
123
120
|
|
|
124
121
|
// Handle error boundary
|
|
125
122
|
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
])
|
|
123
|
+
getHasError({
|
|
124
|
+
result,
|
|
125
|
+
errorResetBoundary,
|
|
126
|
+
useErrorBoundary: defaultedOptions.useErrorBoundary,
|
|
127
|
+
query: observer.getCurrentQuery(),
|
|
128
|
+
})
|
|
133
129
|
) {
|
|
134
130
|
throw result.error
|
|
135
131
|
}
|
package/src/useQueries.ts
CHANGED
|
@@ -6,6 +6,12 @@ import { notifyManager, QueriesObserver } from '@tanstack/query-core'
|
|
|
6
6
|
import { useQueryClient } from './QueryClientProvider'
|
|
7
7
|
import type { UseQueryOptions, UseQueryResult } from './types'
|
|
8
8
|
import { useIsRestoring } from './isRestoring'
|
|
9
|
+
import { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'
|
|
10
|
+
import {
|
|
11
|
+
ensurePreventErrorBoundaryRetry,
|
|
12
|
+
getHasError,
|
|
13
|
+
useClearResetErrorBoundary,
|
|
14
|
+
} from './errorBoundaryUtils'
|
|
9
15
|
|
|
10
16
|
// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
|
|
11
17
|
// - `context` is omitted as it is passed as a root-level option to `useQueries` instead.
|
|
@@ -184,5 +190,26 @@ export function useQueries<T extends any[]>({
|
|
|
184
190
|
observer.setQueries(defaultedQueries, { listeners: false })
|
|
185
191
|
}, [defaultedQueries, observer])
|
|
186
192
|
|
|
193
|
+
const errorResetBoundary = useQueryErrorResetBoundary()
|
|
194
|
+
|
|
195
|
+
defaultedQueries.forEach((query) => {
|
|
196
|
+
ensurePreventErrorBoundaryRetry(query, errorResetBoundary)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
useClearResetErrorBoundary(errorResetBoundary)
|
|
200
|
+
|
|
201
|
+
const firstSingleResultWhichShouldThrow = result.find((singleResult, index) =>
|
|
202
|
+
getHasError({
|
|
203
|
+
result: singleResult,
|
|
204
|
+
errorResetBoundary,
|
|
205
|
+
useErrorBoundary: defaultedQueries[index]?.useErrorBoundary ?? false,
|
|
206
|
+
query: observer.getQueries()[index]!,
|
|
207
|
+
}),
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
if (firstSingleResultWhichShouldThrow?.error) {
|
|
211
|
+
throw firstSingleResultWhichShouldThrow.error
|
|
212
|
+
}
|
|
213
|
+
|
|
187
214
|
return result as QueriesResults<T>
|
|
188
215
|
}
|