@tanstack/preact-query 5.102.8 → 5.103.0

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 (205) hide show
  1. package/build/legacy/HydrationBoundary.cjs +1 -1
  2. package/build/legacy/HydrationBoundary.cjs.map +1 -1
  3. package/build/legacy/HydrationBoundary.js +1 -1
  4. package/build/legacy/HydrationBoundary.js.map +1 -1
  5. package/build/legacy/QueryErrorResetBoundary.cjs +12 -12
  6. package/build/legacy/QueryErrorResetBoundary.cjs.map +1 -1
  7. package/build/legacy/QueryErrorResetBoundary.d.cts +12 -12
  8. package/build/legacy/QueryErrorResetBoundary.d.ts +12 -12
  9. package/build/legacy/QueryErrorResetBoundary.js +12 -12
  10. package/build/legacy/QueryErrorResetBoundary.js.map +1 -1
  11. package/build/legacy/infiniteQueryOptions.cjs.map +1 -1
  12. package/build/legacy/infiniteQueryOptions.d.cts +41 -55
  13. package/build/legacy/infiniteQueryOptions.d.cts.map +1 -1
  14. package/build/legacy/infiniteQueryOptions.d.ts +41 -55
  15. package/build/legacy/infiniteQueryOptions.d.ts.map +1 -1
  16. package/build/legacy/infiniteQueryOptions.js.map +1 -1
  17. package/build/legacy/mutationOptions.cjs.map +1 -1
  18. package/build/legacy/mutationOptions.d.cts +4 -17
  19. package/build/legacy/mutationOptions.d.cts.map +1 -1
  20. package/build/legacy/mutationOptions.d.ts +4 -17
  21. package/build/legacy/mutationOptions.d.ts.map +1 -1
  22. package/build/legacy/mutationOptions.js.map +1 -1
  23. package/build/legacy/queryOptions.cjs.map +1 -1
  24. package/build/legacy/queryOptions.d.cts +51 -74
  25. package/build/legacy/queryOptions.d.cts.map +1 -1
  26. package/build/legacy/queryOptions.d.ts +51 -74
  27. package/build/legacy/queryOptions.d.ts.map +1 -1
  28. package/build/legacy/queryOptions.js.map +1 -1
  29. package/build/legacy/useInfiniteQuery.cjs.map +1 -1
  30. package/build/legacy/useInfiniteQuery.d.cts +208 -36
  31. package/build/legacy/useInfiniteQuery.d.cts.map +1 -1
  32. package/build/legacy/useInfiniteQuery.d.ts +208 -36
  33. package/build/legacy/useInfiniteQuery.d.ts.map +1 -1
  34. package/build/legacy/useInfiniteQuery.js.map +1 -1
  35. package/build/legacy/useIsFetching.cjs +8 -6
  36. package/build/legacy/useIsFetching.cjs.map +1 -1
  37. package/build/legacy/useIsFetching.d.cts +8 -6
  38. package/build/legacy/useIsFetching.d.cts.map +1 -1
  39. package/build/legacy/useIsFetching.d.ts +8 -6
  40. package/build/legacy/useIsFetching.d.ts.map +1 -1
  41. package/build/legacy/useIsFetching.js +8 -6
  42. package/build/legacy/useIsFetching.js.map +1 -1
  43. package/build/legacy/useMutation.cjs +13 -11
  44. package/build/legacy/useMutation.cjs.map +1 -1
  45. package/build/legacy/useMutation.d.cts +13 -11
  46. package/build/legacy/useMutation.d.cts.map +1 -1
  47. package/build/legacy/useMutation.d.ts +13 -11
  48. package/build/legacy/useMutation.d.ts.map +1 -1
  49. package/build/legacy/useMutation.js +13 -11
  50. package/build/legacy/useMutation.js.map +1 -1
  51. package/build/legacy/useMutationState.cjs +49 -29
  52. package/build/legacy/useMutationState.cjs.map +1 -1
  53. package/build/legacy/useMutationState.d.cts +49 -29
  54. package/build/legacy/useMutationState.d.cts.map +1 -1
  55. package/build/legacy/useMutationState.d.ts +49 -29
  56. package/build/legacy/useMutationState.d.ts.map +1 -1
  57. package/build/legacy/useMutationState.js +49 -29
  58. package/build/legacy/useMutationState.js.map +1 -1
  59. package/build/legacy/useQueries.cjs +50 -23
  60. package/build/legacy/useQueries.cjs.map +1 -1
  61. package/build/legacy/useQueries.d.cts +50 -23
  62. package/build/legacy/useQueries.d.cts.map +1 -1
  63. package/build/legacy/useQueries.d.ts +50 -23
  64. package/build/legacy/useQueries.d.ts.map +1 -1
  65. package/build/legacy/useQueries.js +50 -23
  66. package/build/legacy/useQueries.js.map +1 -1
  67. package/build/legacy/useQuery.cjs.map +1 -1
  68. package/build/legacy/useQuery.d.cts +93 -33
  69. package/build/legacy/useQuery.d.cts.map +1 -1
  70. package/build/legacy/useQuery.d.ts +93 -33
  71. package/build/legacy/useQuery.d.ts.map +1 -1
  72. package/build/legacy/useQuery.js.map +1 -1
  73. package/build/legacy/useSuspenseInfiniteQuery.cjs +57 -7
  74. package/build/legacy/useSuspenseInfiniteQuery.cjs.map +1 -1
  75. package/build/legacy/useSuspenseInfiniteQuery.d.cts +57 -7
  76. package/build/legacy/useSuspenseInfiniteQuery.d.cts.map +1 -1
  77. package/build/legacy/useSuspenseInfiniteQuery.d.ts +57 -7
  78. package/build/legacy/useSuspenseInfiniteQuery.d.ts.map +1 -1
  79. package/build/legacy/useSuspenseInfiniteQuery.js +57 -7
  80. package/build/legacy/useSuspenseInfiniteQuery.js.map +1 -1
  81. package/build/legacy/useSuspenseQueries.cjs.map +1 -1
  82. package/build/legacy/useSuspenseQueries.d.cts +244 -20
  83. package/build/legacy/useSuspenseQueries.d.cts.map +1 -1
  84. package/build/legacy/useSuspenseQueries.d.ts +244 -20
  85. package/build/legacy/useSuspenseQueries.d.ts.map +1 -1
  86. package/build/legacy/useSuspenseQueries.js.map +1 -1
  87. package/build/legacy/useSuspenseQuery.cjs +48 -8
  88. package/build/legacy/useSuspenseQuery.cjs.map +1 -1
  89. package/build/legacy/useSuspenseQuery.d.cts +48 -8
  90. package/build/legacy/useSuspenseQuery.d.cts.map +1 -1
  91. package/build/legacy/useSuspenseQuery.d.ts +48 -8
  92. package/build/legacy/useSuspenseQuery.d.ts.map +1 -1
  93. package/build/legacy/useSuspenseQuery.js +48 -8
  94. package/build/legacy/useSuspenseQuery.js.map +1 -1
  95. package/build/modern/HydrationBoundary.cjs +1 -1
  96. package/build/modern/HydrationBoundary.cjs.map +1 -1
  97. package/build/modern/HydrationBoundary.js +1 -1
  98. package/build/modern/HydrationBoundary.js.map +1 -1
  99. package/build/modern/QueryErrorResetBoundary.cjs +12 -12
  100. package/build/modern/QueryErrorResetBoundary.cjs.map +1 -1
  101. package/build/modern/QueryErrorResetBoundary.d.cts +12 -12
  102. package/build/modern/QueryErrorResetBoundary.d.ts +12 -12
  103. package/build/modern/QueryErrorResetBoundary.js +12 -12
  104. package/build/modern/QueryErrorResetBoundary.js.map +1 -1
  105. package/build/modern/infiniteQueryOptions.cjs.map +1 -1
  106. package/build/modern/infiniteQueryOptions.d.cts +41 -55
  107. package/build/modern/infiniteQueryOptions.d.cts.map +1 -1
  108. package/build/modern/infiniteQueryOptions.d.ts +41 -55
  109. package/build/modern/infiniteQueryOptions.d.ts.map +1 -1
  110. package/build/modern/infiniteQueryOptions.js.map +1 -1
  111. package/build/modern/mutationOptions.cjs.map +1 -1
  112. package/build/modern/mutationOptions.d.cts +4 -17
  113. package/build/modern/mutationOptions.d.cts.map +1 -1
  114. package/build/modern/mutationOptions.d.ts +4 -17
  115. package/build/modern/mutationOptions.d.ts.map +1 -1
  116. package/build/modern/mutationOptions.js.map +1 -1
  117. package/build/modern/queryOptions.cjs.map +1 -1
  118. package/build/modern/queryOptions.d.cts +51 -74
  119. package/build/modern/queryOptions.d.cts.map +1 -1
  120. package/build/modern/queryOptions.d.ts +51 -74
  121. package/build/modern/queryOptions.d.ts.map +1 -1
  122. package/build/modern/queryOptions.js.map +1 -1
  123. package/build/modern/useInfiniteQuery.cjs.map +1 -1
  124. package/build/modern/useInfiniteQuery.d.cts +208 -36
  125. package/build/modern/useInfiniteQuery.d.cts.map +1 -1
  126. package/build/modern/useInfiniteQuery.d.ts +208 -36
  127. package/build/modern/useInfiniteQuery.d.ts.map +1 -1
  128. package/build/modern/useInfiniteQuery.js.map +1 -1
  129. package/build/modern/useIsFetching.cjs +8 -6
  130. package/build/modern/useIsFetching.cjs.map +1 -1
  131. package/build/modern/useIsFetching.d.cts +8 -6
  132. package/build/modern/useIsFetching.d.cts.map +1 -1
  133. package/build/modern/useIsFetching.d.ts +8 -6
  134. package/build/modern/useIsFetching.d.ts.map +1 -1
  135. package/build/modern/useIsFetching.js +8 -6
  136. package/build/modern/useIsFetching.js.map +1 -1
  137. package/build/modern/useMutation.cjs +13 -11
  138. package/build/modern/useMutation.cjs.map +1 -1
  139. package/build/modern/useMutation.d.cts +13 -11
  140. package/build/modern/useMutation.d.cts.map +1 -1
  141. package/build/modern/useMutation.d.ts +13 -11
  142. package/build/modern/useMutation.d.ts.map +1 -1
  143. package/build/modern/useMutation.js +13 -11
  144. package/build/modern/useMutation.js.map +1 -1
  145. package/build/modern/useMutationState.cjs +49 -29
  146. package/build/modern/useMutationState.cjs.map +1 -1
  147. package/build/modern/useMutationState.d.cts +49 -29
  148. package/build/modern/useMutationState.d.cts.map +1 -1
  149. package/build/modern/useMutationState.d.ts +49 -29
  150. package/build/modern/useMutationState.d.ts.map +1 -1
  151. package/build/modern/useMutationState.js +49 -29
  152. package/build/modern/useMutationState.js.map +1 -1
  153. package/build/modern/useQueries.cjs +50 -23
  154. package/build/modern/useQueries.cjs.map +1 -1
  155. package/build/modern/useQueries.d.cts +50 -23
  156. package/build/modern/useQueries.d.cts.map +1 -1
  157. package/build/modern/useQueries.d.ts +50 -23
  158. package/build/modern/useQueries.d.ts.map +1 -1
  159. package/build/modern/useQueries.js +50 -23
  160. package/build/modern/useQueries.js.map +1 -1
  161. package/build/modern/useQuery.cjs.map +1 -1
  162. package/build/modern/useQuery.d.cts +93 -33
  163. package/build/modern/useQuery.d.cts.map +1 -1
  164. package/build/modern/useQuery.d.ts +93 -33
  165. package/build/modern/useQuery.d.ts.map +1 -1
  166. package/build/modern/useQuery.js.map +1 -1
  167. package/build/modern/useSuspenseInfiniteQuery.cjs +57 -7
  168. package/build/modern/useSuspenseInfiniteQuery.cjs.map +1 -1
  169. package/build/modern/useSuspenseInfiniteQuery.d.cts +57 -7
  170. package/build/modern/useSuspenseInfiniteQuery.d.cts.map +1 -1
  171. package/build/modern/useSuspenseInfiniteQuery.d.ts +57 -7
  172. package/build/modern/useSuspenseInfiniteQuery.d.ts.map +1 -1
  173. package/build/modern/useSuspenseInfiniteQuery.js +57 -7
  174. package/build/modern/useSuspenseInfiniteQuery.js.map +1 -1
  175. package/build/modern/useSuspenseQueries.cjs.map +1 -1
  176. package/build/modern/useSuspenseQueries.d.cts +244 -20
  177. package/build/modern/useSuspenseQueries.d.cts.map +1 -1
  178. package/build/modern/useSuspenseQueries.d.ts +244 -20
  179. package/build/modern/useSuspenseQueries.d.ts.map +1 -1
  180. package/build/modern/useSuspenseQueries.js.map +1 -1
  181. package/build/modern/useSuspenseQuery.cjs +48 -8
  182. package/build/modern/useSuspenseQuery.cjs.map +1 -1
  183. package/build/modern/useSuspenseQuery.d.cts +48 -8
  184. package/build/modern/useSuspenseQuery.d.cts.map +1 -1
  185. package/build/modern/useSuspenseQuery.d.ts +48 -8
  186. package/build/modern/useSuspenseQuery.d.ts.map +1 -1
  187. package/build/modern/useSuspenseQuery.js +48 -8
  188. package/build/modern/useSuspenseQuery.js.map +1 -1
  189. package/build/query-codemods/eslint.config.js +7 -0
  190. package/build/query-codemods/root.eslint.config.js +45 -0
  191. package/package.json +11 -11
  192. package/src/HydrationBoundary.tsx +0 -1
  193. package/src/QueryErrorResetBoundary.tsx +12 -12
  194. package/src/infiniteQueryOptions.ts +41 -55
  195. package/src/mutationOptions.ts +4 -17
  196. package/src/queryOptions.ts +50 -73
  197. package/src/useInfiniteQuery.ts +208 -36
  198. package/src/useIsFetching.ts +8 -6
  199. package/src/useMutation.ts +13 -11
  200. package/src/useMutationState.ts +49 -29
  201. package/src/useQueries.ts +50 -23
  202. package/src/useQuery.ts +93 -33
  203. package/src/useSuspenseInfiniteQuery.ts +57 -7
  204. package/src/useSuspenseQueries.ts +244 -20
  205. package/src/useSuspenseQuery.ts +48 -8
@@ -12,22 +12,24 @@ import { useQueryClient } from './QueryClientProvider'
12
12
  import { useSyncExternalStore } from './utils'
13
13
 
14
14
  /**
15
- * `useIsMutating` is an optional hook that returns the `number` of mutations that your application is fetching
15
+ * The `useIsMutating` hook returns the `number` of mutations that your application currently has `pending`
16
16
  * (useful for app-wide loading indicators).
17
17
  *
18
18
  * @param filters - The {@link MutationFilters} to narrow down the matched mutations.
19
19
  * @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
20
20
  * be used.
21
- * @returns Will be the `number` of the mutations that your application is currently fetching.
21
+ * @returns Will be the `number` of the mutations that your application currently has `pending`.
22
22
  *
23
23
  * @example
24
24
  * ```tsx
25
25
  * import { useIsMutating } from '@tanstack/preact-query'
26
26
  *
27
- * // How many mutations are fetching?
28
- * const isMutating = useIsMutating()
29
- * // How many mutations matching the posts prefix are fetching?
30
- * const isMutatingPosts = useIsMutating({ mutationKey: ['posts'] })
27
+ * function PostsMutatingIndicator() {
28
+ * // How many mutations matching the posts prefix are in progress?
29
+ * const isMutatingPosts = useIsMutating({ mutationKey: ['posts'] })
30
+ *
31
+ * return isMutatingPosts ? <span>Saving posts...</span> : null
32
+ * }
31
33
  * ```
32
34
  */
33
35
  export function useIsMutating(
@@ -95,10 +97,14 @@ function getResult<
95
97
  * ```tsx
96
98
  * import { useMutationState } from '@tanstack/preact-query'
97
99
  *
98
- * const variables = useMutationState({
99
- * filters: { status: 'pending' },
100
- * select: (mutation) => mutation.state.variables,
101
- * })
100
+ * function PendingPosts() {
101
+ * const pendingVariables = useMutationState({
102
+ * filters: { status: 'pending' },
103
+ * select: (mutation) => mutation.state.variables,
104
+ * })
105
+ *
106
+ * return <>{pendingVariables.length} posts saving...</>
107
+ * }
102
108
  * ```
103
109
  *
104
110
  * @example
@@ -108,30 +114,44 @@ function getResult<
108
114
  *
109
115
  * const mutationKey = ['posts']
110
116
  *
111
- * // Some mutation that we want to get the state for
112
- * const mutation = useMutation({
113
- * mutationKey,
114
- * mutationFn: createPosts,
115
- * })
116
- *
117
- * const data = useMutationState({
118
- * // this mutation key needs to match the mutation key of the given mutation (see above)
119
- * filters: { mutationKey },
120
- * select: (mutation) => mutation.state.data,
121
- * })
117
+ * function Posts() {
118
+ * // Some mutation that we want to get the state for
119
+ * const mutation = useMutation({
120
+ * mutationKey,
121
+ * mutationFn: createPosts,
122
+ * })
123
+ *
124
+ * const savedPosts = useMutationState({
125
+ * // this mutation key needs to match the mutation key of the given mutation (see above)
126
+ * filters: { mutationKey, status: 'success' },
127
+ * select: (mutation) => mutation.state.data,
128
+ * })
129
+ *
130
+ * return (
131
+ * <button onClick={() => mutation.mutate(['New Post'])}>
132
+ * Create post ({savedPosts.length} saved so far)
133
+ * </button>
134
+ * )
135
+ * }
122
136
  * ```
123
137
  *
124
138
  * @example
125
- * Access the latest mutation data via the `mutationKey`. Each invocation of `mutate` adds a new entry to the
126
- * mutation cache for `gcTime` milliseconds — check the last item that `useMutationState` returns to get the
127
- * latest invocation:
139
+ * Access the latest successful mutation data via the `mutationKey`. Each invocation of `mutate` adds a new
140
+ * entry to the mutation cache for `gcTime` milliseconds — with the `status: 'success'` filter below, check the
141
+ * last item that `useMutationState` returns to get the latest successful invocation:
128
142
  * ```tsx
129
- * const data = useMutationState({
130
- * filters: { mutationKey: ['posts'] },
131
- * select: (mutation) => mutation.state.data,
132
- * })
143
+ * import { useMutationState } from '@tanstack/preact-query'
144
+ *
145
+ * function LatestPost() {
146
+ * const savedPosts = useMutationState({
147
+ * filters: { mutationKey: ['posts'], status: 'success' },
148
+ * select: (mutation) => mutation.state.data,
149
+ * })
150
+ *
151
+ * const latestSavedPost = savedPosts[savedPosts.length - 1]
133
152
  *
134
- * const latest = data[data.length - 1]
153
+ * return <>{latestSavedPost ? 'Saved' : 'Nothing saved yet'}</>
154
+ * }
135
155
  * ```
136
156
  */
137
157
  export function useMutationState<
package/src/useQueries.ts CHANGED
@@ -225,8 +225,9 @@ export type QueriesResults<
225
225
  /**
226
226
  * The `useQueries` hook can be used to fetch a variable number of queries.
227
227
  *
228
- * The `queries` key accepts an array with query option objects identical to `useQuery` (excluding the
229
- * `queryClient` option - because the `QueryClient` can be passed in on the top level).
228
+ * The `queries` key accepts an array with query option objects mostly identical to `useQuery` — see the
229
+ * `queries` parameter below for the differences. A custom `QueryClient` is supplied once, as `useQueries`' own
230
+ * top-level second argument, rather than per query.
230
231
  *
231
232
  * Having the same query key more than once in the array of query objects may cause some data to be shared
232
233
  * between queries. To avoid this, consider de-duplicating the queries and map the results back to the desired
@@ -244,32 +245,58 @@ export type QueriesResults<
244
245
  * ```tsx
245
246
  * import { useQueries } from '@tanstack/preact-query'
246
247
  *
247
- * const ids = [1, 2, 3]
248
- * const results = useQueries({
249
- * queries: ids.map((id) => ({
250
- * queryKey: ['post', id],
251
- * queryFn: () => fetchPost(id),
252
- * staleTime: Infinity,
253
- * })),
254
- * })
248
+ * function Posts({ ids }: { ids: Array<number> }) {
249
+ * const postQueries = useQueries({
250
+ * queries: ids.map((id) => ({
251
+ * queryKey: ['post', id],
252
+ * queryFn: () => fetchPost(id),
253
+ * staleTime: Infinity,
254
+ * })),
255
+ * })
256
+ *
257
+ * return (
258
+ * <ul>
259
+ * {postQueries.map((query, index) => {
260
+ * if (query.isPending) return <li key={ids[index]}>Loading...</li>
261
+ * if (query.isError) return <li key={ids[index]}>Error: {query.error.message}</li>
262
+ * return <li key={ids[index]}>{query.data.title}</li>
263
+ * })}
264
+ * </ul>
265
+ * )
266
+ * }
255
267
  * ```
256
268
  *
257
269
  * @example
258
270
  * Combining results into a single value:
259
271
  * ```tsx
260
- * const ids = [1, 2, 3]
261
- * const combinedQueries = useQueries({
262
- * queries: ids.map((id) => ({
263
- * queryKey: ['post', id],
264
- * queryFn: () => fetchPost(id),
265
- * })),
266
- * combine: (results) => {
267
- * return {
268
- * data: results.map((result) => result.data),
269
- * pending: results.some((result) => result.isPending),
270
- * }
271
- * },
272
- * })
272
+ * import { useQueries } from '@tanstack/preact-query'
273
+ *
274
+ * function Posts({ ids }: { ids: Array<number> }) {
275
+ * const { data, isPending, isError } = useQueries({
276
+ * queries: ids.map((id) => ({
277
+ * queryKey: ['post', id],
278
+ * queryFn: () => fetchPost(id),
279
+ * })),
280
+ * combine: (postQueries) => {
281
+ * return {
282
+ * data: postQueries.map((query) => query.data),
283
+ * isPending: postQueries.some((query) => query.isPending),
284
+ * isError: postQueries.some((query) => query.isError),
285
+ * }
286
+ * },
287
+ * })
288
+ *
289
+ * if (isPending) return 'Loading...'
290
+ * if (isError) return 'Error loading posts'
291
+ *
292
+ * return (
293
+ * <ul>
294
+ * {data.map((post) => (
295
+ * <li key={post?.id}>{post?.title}</li>
296
+ * ))}
297
+ * </ul>
298
+ * )
299
+ * }
273
300
  * ```
274
301
  */
275
302
  export function useQueries<
package/src/useQuery.ts CHANGED
@@ -28,14 +28,22 @@ import { useBaseQuery } from './useBaseQuery'
28
28
  * import { useQuery } from '@tanstack/preact-query'
29
29
  *
30
30
  * function Posts() {
31
- * // `data` is `Post[]`, never `undefined`, thanks to `initialData`.
32
- * const { data } = useQuery({
31
+ * // `data` is `Post[]`, never `undefined`, thanks to `initialData` — even if a refetch fails,
32
+ * // so the list stays visible alongside the error.
33
+ * const { data, isError, error } = useQuery({
33
34
  * queryKey: ['posts'],
34
35
  * queryFn: fetchPosts,
35
36
  * initialData: [],
36
37
  * })
37
38
  *
38
- * return <>{data.map((post) => <p key={post.id}>{post.title}</p>)}</>
39
+ * return (
40
+ * <div>
41
+ * {isError ? <span>Error: {error.message}</span> : null}
42
+ * <ul>
43
+ * {data.map((post) => <li key={post.id}>{post.title}</li>)}
44
+ * </ul>
45
+ * </div>
46
+ * )
39
47
  * }
40
48
  * ```
41
49
  */
@@ -54,30 +62,30 @@ export function useQuery<
54
62
  * @param options - The {@link UndefinedInitialDataOptions} to use — everything you can pass to `useQuery`.
55
63
  * @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
56
64
  * be used.
57
- * @returns The current query result. `status` is `pending` if there is no cached data and no query attempt
58
- * has finished yet, `error` if the query attempt resulted in an error, or `success` if the query has data to
59
- * display. `isPending`/`isSuccess`/`isError` are derived booleans for convenience.
65
+ * @returns The current query result. `status` is `pending` if there is no cached data to display, `error` if
66
+ * the last fetch attempt failed, or `success` if the query has data to display. `isPending`/`isSuccess`/`isError`
67
+ * are derived booleans for convenience.
60
68
  *
61
69
  * @example
62
70
  * ```tsx
63
- * import { queryOptions, useQuery } from '@tanstack/preact-query'
64
- *
65
- * const postsOptions = queryOptions({
66
- * queryKey: ['posts'],
67
- * queryFn: fetchPosts,
68
- * })
71
+ * import { useQuery } from '@tanstack/preact-query'
69
72
  *
70
73
  * function Posts() {
71
- * const { status, data, error, isFetching } = useQuery(postsOptions)
74
+ * const { status, data, error, isFetching } = useQuery({
75
+ * queryKey: ['posts'],
76
+ * queryFn: fetchPosts,
77
+ * })
72
78
  *
73
79
  * if (status === 'pending') return 'Loading...'
74
80
  * if (status === 'error') return <span>Error: {error.message}</span>
75
81
  *
76
82
  * return (
77
83
  * <div>
78
- * {data.map((post) => (
79
- * <p key={post.id}>{post.title}</p>
80
- * ))}
84
+ * <ul>
85
+ * {data.map((post) => (
86
+ * <li key={post.id}>{post.title}</li>
87
+ * ))}
88
+ * </ul>
81
89
  * <div>{isFetching ? 'Background Updating...' : ' '}</div>
82
90
  * </div>
83
91
  * )
@@ -98,7 +106,11 @@ export function useQuery<
98
106
  * if (isPending) return 'Loading...'
99
107
  * if (isError) return <span>Error: {error.message}</span>
100
108
  *
101
- * return <>{data.map((post) => <p key={post.id}>{post.title}</p>)}</>
109
+ * return (
110
+ * <ul>
111
+ * {data.map((post) => <li key={post.id}>{post.title}</li>)}
112
+ * </ul>
113
+ * )
102
114
  * }
103
115
  * ```
104
116
  */
@@ -117,30 +129,30 @@ export function useQuery<
117
129
  * @param options - The {@link UseQueryOptions} to use — everything you can pass to `useQuery`.
118
130
  * @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
119
131
  * be used.
120
- * @returns The current query result. `status` is `pending` if there is no cached data and no query attempt
121
- * has finished yet, `error` if the query attempt resulted in an error, or `success` if the query has data to
122
- * display. `isPending`/`isSuccess`/`isError` are derived booleans for convenience.
132
+ * @returns The current query result. `status` is `pending` if there is no cached data to display, `error` if
133
+ * the last fetch attempt failed, or `success` if the query has data to display. `isPending`/`isSuccess`/`isError`
134
+ * are derived booleans for convenience.
123
135
  *
124
136
  * @example
125
137
  * ```tsx
126
- * import { queryOptions, useQuery } from '@tanstack/preact-query'
127
- *
128
- * const postsOptions = queryOptions({
129
- * queryKey: ['posts'],
130
- * queryFn: fetchPosts,
131
- * })
138
+ * import { useQuery } from '@tanstack/preact-query'
132
139
  *
133
140
  * function Posts() {
134
- * const { status, data, error, isFetching } = useQuery(postsOptions)
141
+ * const { status, data, error, isFetching } = useQuery({
142
+ * queryKey: ['posts'],
143
+ * queryFn: fetchPosts,
144
+ * })
135
145
  *
136
146
  * if (status === 'pending') return 'Loading...'
137
147
  * if (status === 'error') return <span>Error: {error.message}</span>
138
148
  *
139
149
  * return (
140
150
  * <div>
141
- * {data.map((post) => (
142
- * <p key={post.id}>{post.title}</p>
143
- * ))}
151
+ * <ul>
152
+ * {data.map((post) => (
153
+ * <li key={post.id}>{post.title}</li>
154
+ * ))}
155
+ * </ul>
144
156
  * <div>{isFetching ? 'Background Updating...' : ' '}</div>
145
157
  * </div>
146
158
  * )
@@ -148,6 +160,26 @@ export function useQuery<
148
160
  * ```
149
161
  *
150
162
  * @example
163
+ * `select` derives whatever `data` a component needs from the cached value, without changing what's
164
+ * actually stored in the cache — the cache still holds the full `Post[]`, but `data` here is a `number`:
165
+ * ```tsx
166
+ * import { useQuery } from '@tanstack/preact-query'
167
+ *
168
+ * function PostCount() {
169
+ * const { data, isPending, isError, error } = useQuery({
170
+ * queryKey: ['posts'],
171
+ * queryFn: fetchPosts,
172
+ * select: (posts) => posts.length,
173
+ * })
174
+ *
175
+ * if (isPending) return 'Loading...'
176
+ * if (isError) return <span>Error: {error.message}</span>
177
+ *
178
+ * return <span>{data} posts</span>
179
+ * }
180
+ * ```
181
+ *
182
+ * @example
151
183
  * A dependent query, only enabled once `postId` is set — use `isLoading`, not `isPending`, so the
152
184
  * loading state doesn't show while the query is disabled:
153
185
  * ```tsx
@@ -169,6 +201,28 @@ export function useQuery<
169
201
  * ```
170
202
  *
171
203
  * @example
204
+ * The same dependent query, type safe: `skipToken` disables the query without needing the
205
+ * non-null assertion above, since `queryFn` is only ever called when `postId` is defined.
206
+ * `refetch` doesn't work while `queryFn` is `skipToken` — use `enabled: false` instead if you
207
+ * need to trigger the query manually:
208
+ * ```tsx
209
+ * import { skipToken, useQuery } from '@tanstack/preact-query'
210
+ *
211
+ * function Post({ postId }: { postId: number | undefined }) {
212
+ * const { data, isLoading, isError, error } = useQuery({
213
+ * queryKey: ['post', postId],
214
+ * queryFn: postId != null ? () => fetchPost(postId) : skipToken,
215
+ * })
216
+ *
217
+ * if (postId == null) return 'Select a post'
218
+ * if (isLoading) return 'Loading...'
219
+ * if (isError) return <span>Error: {error.message}</span>
220
+ *
221
+ * return <h1>{data?.title}</h1>
222
+ * }
223
+ * ```
224
+ *
225
+ * @example
172
226
  * Seeding a detail query from an already-cached list, to skip the loading state:
173
227
  * ```tsx
174
228
  * import { useQuery, useQueryClient } from '@tanstack/preact-query'
@@ -176,7 +230,7 @@ export function useQuery<
176
230
  * function Post({ postId }: { postId: number }) {
177
231
  * const queryClient = useQueryClient()
178
232
  *
179
- * const { data } = useQuery({
233
+ * const { data, isError, error } = useQuery({
180
234
  * queryKey: ['post', postId],
181
235
  * queryFn: () => fetchPost(postId),
182
236
  * initialData: () =>
@@ -185,6 +239,8 @@ export function useQuery<
185
239
  * ?.find((post) => post.id === postId),
186
240
  * })
187
241
  *
242
+ * if (isError) return <span>Error: {error.message}</span>
243
+ *
188
244
  * return <h1>{data?.title}</h1>
189
245
  * }
190
246
  * ```
@@ -198,15 +254,19 @@ export function useQuery<
198
254
  * function Posts() {
199
255
  * const [page, setPage] = useState(0)
200
256
  *
201
- * const { data, isPlaceholderData } = useQuery({
257
+ * const { data, isPlaceholderData, isError, error } = useQuery({
202
258
  * queryKey: ['posts', page],
203
259
  * queryFn: () => fetchPosts(page),
204
260
  * placeholderData: keepPreviousData,
205
261
  * })
206
262
  *
263
+ * if (isError) return <span>Error: {error.message}</span>
264
+ *
207
265
  * return (
208
266
  * <div>
209
- * {data?.map((post) => <p key={post.id}>{post.title}</p>)}
267
+ * <ul>
268
+ * {data?.map((post) => <li key={post.id}>{post.title}</li>)}
269
+ * </ul>
210
270
  * <button
211
271
  * disabled={isPlaceholderData}
212
272
  * onClick={() => setPage((old) => old + 1)}
@@ -21,6 +21,13 @@ import { useBaseQuery } from './useBaseQuery'
21
21
  *
22
22
  * Caveat: cancellation does not work.
23
23
  *
24
+ * @remarks Multiple suspenseful query calls in the same component suspend serially, causing a request
25
+ * waterfall — each one blocks rendering until it resolves, so the next doesn't even start fetching until
26
+ * then. There's no way to parallelize multiple infinite queries under Suspense. Also keep in mind that
27
+ * imperative fetch calls, such as `fetchNextPage`, may interfere with the default refetch behavior,
28
+ * resulting in outdated data. Make sure to call these functions only in response to user actions, or add
29
+ * conditions like `hasNextPage && !isFetching`.
30
+ * @see {@link useInfiniteQuery} for the non-Suspense version of this hook.
24
31
  * @param options - The {@link UseSuspenseInfiniteQueryOptions} to use — the same options as `useInfiniteQuery`, minus the ones listed above.
25
32
  * @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
26
33
  * be used.
@@ -29,9 +36,17 @@ import { useBaseQuery } from './useBaseQuery'
29
36
  * accordingly).
30
37
  *
31
38
  * @example
39
+ * The query error is thrown if a fetch fails and no cached data exists yet, so an error boundary is
40
+ * required around `<Suspense>`. A failed background refetch instead continues to render the cached data.
41
+ * Use {@link QueryErrorResetBoundary} to let the user retry after such an error:
32
42
  * ```tsx
33
43
  * import { Suspense } from 'preact/compat'
34
- * import { useSuspenseInfiniteQuery } from '@tanstack/preact-query'
44
+ * import { useErrorBoundary } from 'preact/hooks'
45
+ * import {
46
+ * QueryErrorResetBoundary,
47
+ * useSuspenseInfiniteQuery,
48
+ * } from '@tanstack/preact-query'
49
+ * import type { ComponentChildren } from 'preact'
35
50
  *
36
51
  * function Projects() {
37
52
  * // `data` is guaranteed to be defined here — no `isPending` check needed.
@@ -45,9 +60,11 @@ import { useBaseQuery } from './useBaseQuery'
45
60
  *
46
61
  * return (
47
62
  * <div>
48
- * {data.pages.map((page) =>
49
- * page.projects.map((project) => <p key={project.id}>{project.name}</p>),
50
- * )}
63
+ * <ul>
64
+ * {data.pages.map((page) =>
65
+ * page.projects.map((project) => <li key={project.id}>{project.name}</li>),
66
+ * )}
67
+ * </ul>
51
68
  * <button
52
69
  * onClick={() => fetchNextPage()}
53
70
  * disabled={!hasNextPage || isFetching}
@@ -64,11 +81,44 @@ import { useBaseQuery } from './useBaseQuery'
64
81
  *
65
82
  * function App() {
66
83
  * return (
67
- * <Suspense fallback={<h1>Loading projects...</h1>}>
68
- * <Projects />
69
- * </Suspense>
84
+ * <QueryErrorResetBoundary>
85
+ * {({ reset }) => (
86
+ * <ErrorBoundary
87
+ * onReset={reset}
88
+ * fallbackRender={({ resetErrorBoundary }) => (
89
+ * <div>
90
+ * There was an error!
91
+ * <button onClick={() => resetErrorBoundary()}>Try again</button>
92
+ * </div>
93
+ * )}
94
+ * >
95
+ * <Suspense fallback={<h1>Loading projects...</h1>}>
96
+ * <Projects />
97
+ * </Suspense>
98
+ * </ErrorBoundary>
99
+ * )}
100
+ * </QueryErrorResetBoundary>
70
101
  * )
71
102
  * }
103
+ *
104
+ * function ErrorBoundary({
105
+ * children,
106
+ * onReset,
107
+ * fallbackRender,
108
+ * }: {
109
+ * children: ComponentChildren
110
+ * onReset: () => void
111
+ * fallbackRender: (props: {
112
+ * error: Error
113
+ * resetErrorBoundary: () => void
114
+ * }) => ComponentChildren
115
+ * }) {
116
+ * const [error, resetErrorBoundary] = useErrorBoundary(() => onReset())
117
+ *
118
+ * if (error) return fallbackRender({ error, resetErrorBoundary })
119
+ *
120
+ * return children
121
+ * }
72
122
  * ```
73
123
  */
74
124
  export function useSuspenseInfiniteQuery<