@tanstack/svelte-query 6.1.48 → 6.2.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/dist/context.d.ts +27 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +27 -2
- package/dist/createInfiniteQuery.d.ts +97 -1
- package/dist/createInfiniteQuery.d.ts.map +1 -1
- package/dist/createMutation.svelte.d.ts +156 -2
- package/dist/createMutation.svelte.d.ts.map +1 -1
- package/dist/createMutation.svelte.js +156 -2
- package/dist/createQueries.svelte.d.ts +71 -0
- package/dist/createQueries.svelte.d.ts.map +1 -1
- package/dist/createQueries.svelte.js +71 -0
- package/dist/createQuery.d.ts +209 -0
- package/dist/createQuery.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/infiniteQueryOptions.d.ts +95 -2
- package/dist/infiniteQueryOptions.d.ts.map +1 -1
- package/dist/mutationOptions.d.ts +52 -0
- package/dist/mutationOptions.d.ts.map +1 -1
- package/dist/queryOptions.d.ts +73 -0
- package/dist/queryOptions.d.ts.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/useHydrate.d.ts +28 -0
- package/dist/useHydrate.d.ts.map +1 -1
- package/dist/useHydrate.js +28 -0
- package/dist/useIsFetching.svelte.d.ts +35 -0
- package/dist/useIsFetching.svelte.d.ts.map +1 -1
- package/dist/useIsFetching.svelte.js +35 -0
- package/dist/useIsMutating.svelte.d.ts +23 -0
- package/dist/useIsMutating.svelte.d.ts.map +1 -1
- package/dist/useIsMutating.svelte.js +23 -0
- package/dist/useMutationState.svelte.d.ts +70 -0
- package/dist/useMutationState.svelte.d.ts.map +1 -1
- package/dist/useMutationState.svelte.js +70 -0
- package/package.json +3 -3
- package/src/context.ts +27 -2
- package/src/createInfiniteQuery.ts +143 -2
- package/src/createMutation.svelte.ts +156 -2
- package/src/createQueries.svelte.ts +71 -0
- package/src/createQuery.ts +209 -0
- package/src/index.ts +4 -0
- package/src/infiniteQueryOptions.ts +162 -4
- package/src/mutationOptions.ts +53 -0
- package/src/queryOptions.ts +73 -0
- package/src/types.ts +7 -0
- package/src/useHydrate.ts +28 -0
- package/src/useIsFetching.svelte.ts +35 -0
- package/src/useIsMutating.svelte.ts +23 -0
- package/src/useMutationState.svelte.ts +70 -0
|
@@ -11,8 +11,162 @@ import type {
|
|
|
11
11
|
import type { DefaultError, QueryClient } from '@tanstack/query-core'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.
|
|
15
|
+
* `createMutation` is the function for that.
|
|
16
|
+
*
|
|
17
|
+
* @see {@link mutationOptions} to share these options across multiple `createMutation` call sites, or to look
|
|
18
|
+
* the mutation up elsewhere via its `mutationKey` (e.g. with `useMutationState`).
|
|
19
|
+
* @param options - The {@link CreateMutationOptions} to use, wrapped in an {@link Accessor} so options can be
|
|
20
|
+
* reactive.
|
|
21
|
+
* @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
|
|
22
|
+
* be used.
|
|
23
|
+
* @returns `mutate`/`mutateAsync` also accept per-call `onSuccess`/`onError`/`onSettled` callbacks as a second
|
|
24
|
+
* argument, useful for triggering call-site side effects (e.g. navigation) without coupling them to the shared
|
|
25
|
+
* mutation definition. If you make multiple requests, `onSuccess` will fire only after the latest call you've
|
|
26
|
+
* made.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```svelte
|
|
30
|
+
* <script lang="ts">
|
|
31
|
+
* import { createMutation, useQueryClient } from '@tanstack/svelte-query'
|
|
32
|
+
*
|
|
33
|
+
* const queryClient = useQueryClient()
|
|
34
|
+
*
|
|
35
|
+
* const addMutation = createMutation(() => ({
|
|
36
|
+
* mutationFn: addTodo,
|
|
37
|
+
* onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
38
|
+
* }))
|
|
39
|
+
* </script>
|
|
40
|
+
*
|
|
41
|
+
* <button
|
|
42
|
+
* onclick={() =>
|
|
43
|
+
* addMutation.mutate('Item', {
|
|
44
|
+
* onError: (error) => console.error('Failed to add item:', error),
|
|
45
|
+
* })
|
|
46
|
+
* }
|
|
47
|
+
* >
|
|
48
|
+
* Add
|
|
49
|
+
* </button>
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* Rendering the mutation's own state, rather than just firing it off:
|
|
54
|
+
* ```svelte
|
|
55
|
+
* <script lang="ts">
|
|
56
|
+
* import { createMutation, useQueryClient } from '@tanstack/svelte-query'
|
|
57
|
+
*
|
|
58
|
+
* const queryClient = useQueryClient()
|
|
59
|
+
*
|
|
60
|
+
* const addMutation = createMutation(() => ({
|
|
61
|
+
* mutationFn: addTodo,
|
|
62
|
+
* onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
63
|
+
* }))
|
|
64
|
+
* </script>
|
|
65
|
+
*
|
|
66
|
+
* {#if addMutation.isPending}
|
|
67
|
+
* Adding todo...
|
|
68
|
+
* {:else}
|
|
69
|
+
* {#if addMutation.isError}
|
|
70
|
+
* <div>An error occurred: {addMutation.error.message}</div>
|
|
71
|
+
* {/if}
|
|
72
|
+
* <button onclick={() => addMutation.mutate('Item')}>Add</button>
|
|
73
|
+
* {/if}
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* Optimistic update via `onMutate`, rolling back on `onError`:
|
|
78
|
+
* ```svelte
|
|
79
|
+
* <script lang="ts">
|
|
80
|
+
* import { createMutation, useQueryClient } from '@tanstack/svelte-query'
|
|
81
|
+
*
|
|
82
|
+
* const queryClient = useQueryClient()
|
|
83
|
+
*
|
|
84
|
+
* const addMutation = createMutation(() => ({
|
|
85
|
+
* mutationFn: addTodo,
|
|
86
|
+
* onMutate: async (newTodo: string) => {
|
|
87
|
+
* await queryClient.cancelQueries({ queryKey: ['todos'] })
|
|
88
|
+
* const previousTodos = queryClient.getQueryData<Array<string>>(['todos'])
|
|
89
|
+
*
|
|
90
|
+
* queryClient.setQueryData<Array<string>>(['todos'], (old) => [
|
|
91
|
+
* ...(old ?? []),
|
|
92
|
+
* newTodo,
|
|
93
|
+
* ])
|
|
94
|
+
*
|
|
95
|
+
* // Passed to `onError` as `onMutateResult` if the mutation fails.
|
|
96
|
+
* return { previousTodos }
|
|
97
|
+
* },
|
|
98
|
+
* onError: (_err, _newTodo, onMutateResult) => {
|
|
99
|
+
* queryClient.setQueryData(['todos'], onMutateResult?.previousTodos)
|
|
100
|
+
* },
|
|
101
|
+
* onSettled: () => {
|
|
102
|
+
* queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
103
|
+
* },
|
|
104
|
+
* }))
|
|
105
|
+
* </script>
|
|
106
|
+
*
|
|
107
|
+
* <button onclick={() => addMutation.mutate('Item')}>Add</button>
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* Callbacks passed per call to `mutate` only fire for the last call — `mutateAsync` gives you a
|
|
112
|
+
* promise per call instead, so you can wait for all of them when they succeed:
|
|
113
|
+
* ```svelte
|
|
114
|
+
* <script lang="ts">
|
|
115
|
+
* import { createMutation, useQueryClient } from '@tanstack/svelte-query'
|
|
116
|
+
*
|
|
117
|
+
* const queryClient = useQueryClient()
|
|
118
|
+
*
|
|
119
|
+
* const addMutation = createMutation(() => ({
|
|
120
|
+
* mutationFn: addTodo,
|
|
121
|
+
* onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
122
|
+
* }))
|
|
123
|
+
*
|
|
124
|
+
* async function handleAddAll(todos: Array<string>) {
|
|
125
|
+
* try {
|
|
126
|
+
* await Promise.all(todos.map((todo) => addMutation.mutateAsync(todo)))
|
|
127
|
+
* } catch (error) {
|
|
128
|
+
* console.error('Failed to add todos:', error)
|
|
129
|
+
* }
|
|
130
|
+
* }
|
|
131
|
+
* </script>
|
|
132
|
+
*
|
|
133
|
+
* <button onclick={() => handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])}>
|
|
134
|
+
* Add all
|
|
135
|
+
* </button>
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* If some of the mutations above can fail independently of the others, and you want to know which ones
|
|
140
|
+
* did — rather than losing that information the moment the first one rejects — swap `Promise.all` for
|
|
141
|
+
* `Promise.allSettled`:
|
|
142
|
+
* ```svelte
|
|
143
|
+
* <script lang="ts">
|
|
144
|
+
* import { createMutation, useQueryClient } from '@tanstack/svelte-query'
|
|
145
|
+
*
|
|
146
|
+
* const queryClient = useQueryClient()
|
|
147
|
+
*
|
|
148
|
+
* const addMutation = createMutation(() => ({
|
|
149
|
+
* mutationFn: addTodo,
|
|
150
|
+
* onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
151
|
+
* }))
|
|
152
|
+
*
|
|
153
|
+
* async function handleAddAll(todos: Array<string>) {
|
|
154
|
+
* const addResults = await Promise.allSettled(
|
|
155
|
+
* todos.map((todo) => addMutation.mutateAsync(todo)),
|
|
156
|
+
* )
|
|
157
|
+
*
|
|
158
|
+
* addResults.forEach((addResult, index) => {
|
|
159
|
+
* if (addResult.status === 'rejected') {
|
|
160
|
+
* console.error(`Failed to add "${todos[index]}":`, addResult.reason)
|
|
161
|
+
* }
|
|
162
|
+
* })
|
|
163
|
+
* }
|
|
164
|
+
* </script>
|
|
165
|
+
*
|
|
166
|
+
* <button onclick={() => handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])}>
|
|
167
|
+
* Add all
|
|
168
|
+
* </button>
|
|
169
|
+
* ```
|
|
16
170
|
*/
|
|
17
171
|
export function createMutation<
|
|
18
172
|
TData = unknown,
|
|
@@ -186,6 +186,77 @@ export type QueriesResults<
|
|
|
186
186
|
>
|
|
187
187
|
: { [K in keyof T]: GetCreateQueryResult<T[K]> }
|
|
188
188
|
|
|
189
|
+
/**
|
|
190
|
+
* @param createQueriesOptions - The `queries` array to run, and an optional `combine` function, wrapped in an
|
|
191
|
+
* {@link Accessor} so options can be reactive.
|
|
192
|
+
* @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context
|
|
193
|
+
* will be used.
|
|
194
|
+
* @returns An array with one result per query, in the same order as `queries` — or, if `combine` is provided,
|
|
195
|
+
* whatever `combine` returns.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```svelte
|
|
199
|
+
* <script lang="ts">
|
|
200
|
+
* import { createQueries } from '@tanstack/svelte-query'
|
|
201
|
+
*
|
|
202
|
+
* let { ids }: { ids: Array<number> } = $props()
|
|
203
|
+
*
|
|
204
|
+
* const postQueries = createQueries(() => ({
|
|
205
|
+
* queries: ids.map((id) => ({
|
|
206
|
+
* queryKey: ['post', id],
|
|
207
|
+
* queryFn: () => fetchPost(id),
|
|
208
|
+
* staleTime: Infinity,
|
|
209
|
+
* })),
|
|
210
|
+
* }))
|
|
211
|
+
* </script>
|
|
212
|
+
*
|
|
213
|
+
* <ul>
|
|
214
|
+
* {#each postQueries as query, index (ids[index])}
|
|
215
|
+
* {#if query.isPending}
|
|
216
|
+
* <li>Loading...</li>
|
|
217
|
+
* {:else if query.isError}
|
|
218
|
+
* <li>Error: {query.error.message}</li>
|
|
219
|
+
* {:else}
|
|
220
|
+
* <li>{query.data.title}</li>
|
|
221
|
+
* {/if}
|
|
222
|
+
* {/each}
|
|
223
|
+
* </ul>
|
|
224
|
+
* ```
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* Combining results into a single value:
|
|
228
|
+
* ```svelte
|
|
229
|
+
* <script lang="ts">
|
|
230
|
+
* import { createQueries } from '@tanstack/svelte-query'
|
|
231
|
+
*
|
|
232
|
+
* let { ids }: { ids: Array<number> } = $props()
|
|
233
|
+
*
|
|
234
|
+
* const combined = createQueries(() => ({
|
|
235
|
+
* queries: ids.map((id) => ({
|
|
236
|
+
* queryKey: ['post', id],
|
|
237
|
+
* queryFn: () => fetchPost(id),
|
|
238
|
+
* })),
|
|
239
|
+
* combine: (postQueries) => ({
|
|
240
|
+
* data: postQueries.map((query) => query.data),
|
|
241
|
+
* isPending: postQueries.some((query) => query.isPending),
|
|
242
|
+
* isError: postQueries.some((query) => query.isError),
|
|
243
|
+
* }),
|
|
244
|
+
* }))
|
|
245
|
+
* </script>
|
|
246
|
+
*
|
|
247
|
+
* {#if combined.isPending}
|
|
248
|
+
* Loading...
|
|
249
|
+
* {:else if combined.isError}
|
|
250
|
+
* Error loading posts
|
|
251
|
+
* {:else}
|
|
252
|
+
* <ul>
|
|
253
|
+
* {#each combined.data as post}
|
|
254
|
+
* <li>{post?.title}</li>
|
|
255
|
+
* {/each}
|
|
256
|
+
* </ul>
|
|
257
|
+
* {/if}
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
189
260
|
export function createQueries<
|
|
190
261
|
T extends Array<any>,
|
|
191
262
|
TCombinedResult = QueriesResults<T>,
|
package/src/createQuery.ts
CHANGED
|
@@ -12,6 +12,65 @@ import type {
|
|
|
12
12
|
UndefinedInitialDataOptions,
|
|
13
13
|
} from './queryOptions.js'
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @see {@link queryOptions} to share these options between `createQuery` and imperative APIs like `queryClient.query`.
|
|
17
|
+
* @param options - The {@link UndefinedInitialDataOptions} to use — everything you can pass to `createQuery`,
|
|
18
|
+
* wrapped in an {@link Accessor} so options can be reactive.
|
|
19
|
+
* @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
|
|
20
|
+
* be used.
|
|
21
|
+
* @returns The current query result. `status` is `pending` if there is no cached data to display, `error` if
|
|
22
|
+
* the last fetch attempt failed, or `success` if the query has data to display. `isPending`/`isSuccess`/`isError`
|
|
23
|
+
* are derived booleans for convenience.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```svelte
|
|
27
|
+
* <script lang="ts">
|
|
28
|
+
* import { createQuery } from '@tanstack/svelte-query'
|
|
29
|
+
*
|
|
30
|
+
* const query = createQuery(() => ({
|
|
31
|
+
* queryKey: ['posts'],
|
|
32
|
+
* queryFn: fetchPosts,
|
|
33
|
+
* }))
|
|
34
|
+
* </script>
|
|
35
|
+
*
|
|
36
|
+
* {#if query.status === 'pending'}
|
|
37
|
+
* Loading...
|
|
38
|
+
* {:else if query.status === 'error'}
|
|
39
|
+
* <span>Error: {query.error.message}</span>
|
|
40
|
+
* {:else}
|
|
41
|
+
* <ul>
|
|
42
|
+
* {#each query.data as post (post.id)}
|
|
43
|
+
* <li>{post.title}</li>
|
|
44
|
+
* {/each}
|
|
45
|
+
* </ul>
|
|
46
|
+
* {/if}
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* The same query, checking `isPending`/`isError` instead of `status` — pick whichever reads better to you:
|
|
51
|
+
* ```svelte
|
|
52
|
+
* <script lang="ts">
|
|
53
|
+
* import { createQuery } from '@tanstack/svelte-query'
|
|
54
|
+
*
|
|
55
|
+
* const query = createQuery(() => ({
|
|
56
|
+
* queryKey: ['posts'],
|
|
57
|
+
* queryFn: fetchPosts,
|
|
58
|
+
* }))
|
|
59
|
+
* </script>
|
|
60
|
+
*
|
|
61
|
+
* {#if query.isPending}
|
|
62
|
+
* Loading...
|
|
63
|
+
* {:else if query.isError}
|
|
64
|
+
* <span>Error: {query.error.message}</span>
|
|
65
|
+
* {:else}
|
|
66
|
+
* <ul>
|
|
67
|
+
* {#each query.data as post (post.id)}
|
|
68
|
+
* <li>{post.title}</li>
|
|
69
|
+
* {/each}
|
|
70
|
+
* </ul>
|
|
71
|
+
* {/if}
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
15
74
|
export function createQuery<
|
|
16
75
|
TQueryFnData = unknown,
|
|
17
76
|
TError = DefaultError,
|
|
@@ -24,6 +83,42 @@ export function createQuery<
|
|
|
24
83
|
queryClient?: Accessor<QueryClient>,
|
|
25
84
|
): CreateQueryResult<TData, TError>
|
|
26
85
|
|
|
86
|
+
/**
|
|
87
|
+
* This overload is selected when `initialData` is set, so the resulting `data` is never `undefined`.
|
|
88
|
+
*
|
|
89
|
+
* @see {@link queryOptions} to share these options between `createQuery` and imperative APIs like `queryClient.query`.
|
|
90
|
+
* @param options - The {@link DefinedInitialDataOptions} to use — everything you can pass to `createQuery`,
|
|
91
|
+
* with `initialData` set, wrapped in an {@link Accessor} so options can be reactive.
|
|
92
|
+
* @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
|
|
93
|
+
* be used.
|
|
94
|
+
* @returns The current query result, typed so that `status` is `success` — or `error` if a fetch attempt
|
|
95
|
+
* fails while keeping the existing data (`status` never resolves to `pending` in this overload's type,
|
|
96
|
+
* since `initialData` guarantees data upfront). `isSuccess`/`isError` are derived booleans for convenience.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```svelte
|
|
100
|
+
* <script lang="ts">
|
|
101
|
+
* import { createQuery } from '@tanstack/svelte-query'
|
|
102
|
+
*
|
|
103
|
+
* // `data` is `Post[]`, never `undefined`, thanks to `initialData` — even if a refetch fails,
|
|
104
|
+
* // so the list stays visible alongside the error.
|
|
105
|
+
* const query = createQuery(() => ({
|
|
106
|
+
* queryKey: ['posts'],
|
|
107
|
+
* queryFn: fetchPosts,
|
|
108
|
+
* initialData: [],
|
|
109
|
+
* }))
|
|
110
|
+
* </script>
|
|
111
|
+
*
|
|
112
|
+
* {#if query.isError}
|
|
113
|
+
* <span>Error: {query.error.message}</span>
|
|
114
|
+
* {/if}
|
|
115
|
+
* <ul>
|
|
116
|
+
* {#each query.data as post (post.id)}
|
|
117
|
+
* <li>{post.title}</li>
|
|
118
|
+
* {/each}
|
|
119
|
+
* </ul>
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
27
122
|
export function createQuery<
|
|
28
123
|
TQueryFnData = unknown,
|
|
29
124
|
TError = DefaultError,
|
|
@@ -36,6 +131,120 @@ export function createQuery<
|
|
|
36
131
|
queryClient?: Accessor<QueryClient>,
|
|
37
132
|
): DefinedCreateQueryResult<TData, TError>
|
|
38
133
|
|
|
134
|
+
/**
|
|
135
|
+
* @see {@link queryOptions} to share these options between `createQuery` and imperative APIs like `queryClient.query`.
|
|
136
|
+
* @param options - The {@link CreateQueryOptions} to use — everything you can pass to `createQuery`, wrapped
|
|
137
|
+
* in an {@link Accessor} so options can be reactive.
|
|
138
|
+
* @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
|
|
139
|
+
* be used.
|
|
140
|
+
* @returns The current query result. `status` is `pending` if there is no cached data to display, `error` if
|
|
141
|
+
* the last fetch attempt failed, or `success` if the query has data to display. `isPending`/`isSuccess`/`isError`
|
|
142
|
+
* are derived booleans for convenience.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* `select` derives whatever `data` a component needs from the cached value, without changing what's
|
|
146
|
+
* actually stored in the cache — the cache still holds the full `Post[]`, but `data` here is a `number`:
|
|
147
|
+
* ```svelte
|
|
148
|
+
* <script lang="ts">
|
|
149
|
+
* import { createQuery } from '@tanstack/svelte-query'
|
|
150
|
+
*
|
|
151
|
+
* const query = createQuery(() => ({
|
|
152
|
+
* queryKey: ['posts'],
|
|
153
|
+
* queryFn: fetchPosts,
|
|
154
|
+
* select: (posts) => posts.length,
|
|
155
|
+
* }))
|
|
156
|
+
* </script>
|
|
157
|
+
*
|
|
158
|
+
* {#if query.isPending}
|
|
159
|
+
* Loading...
|
|
160
|
+
* {:else if query.isError}
|
|
161
|
+
* <span>Error: {query.error.message}</span>
|
|
162
|
+
* {:else}
|
|
163
|
+
* <span>{query.data} posts</span>
|
|
164
|
+
* {/if}
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* A dependent query, only enabled once `postId` is set — use `isLoading`, not `isPending`, so the
|
|
169
|
+
* loading state doesn't show while the query is disabled:
|
|
170
|
+
* ```svelte
|
|
171
|
+
* <script lang="ts">
|
|
172
|
+
* import { createQuery } from '@tanstack/svelte-query'
|
|
173
|
+
*
|
|
174
|
+
* let { postId }: { postId: number | undefined } = $props()
|
|
175
|
+
*
|
|
176
|
+
* const query = createQuery(() => ({
|
|
177
|
+
* queryKey: ['post', postId],
|
|
178
|
+
* queryFn: () => fetchPost(postId!),
|
|
179
|
+
* enabled: postId != null,
|
|
180
|
+
* }))
|
|
181
|
+
* </script>
|
|
182
|
+
*
|
|
183
|
+
* {#if postId == null}
|
|
184
|
+
* Select a post
|
|
185
|
+
* {:else if query.isLoading}
|
|
186
|
+
* Loading...
|
|
187
|
+
* {:else if query.isError}
|
|
188
|
+
* <span>Error: {query.error.message}</span>
|
|
189
|
+
* {:else}
|
|
190
|
+
* <h1>{query.data?.title}</h1>
|
|
191
|
+
* {/if}
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* Seeding a detail query from an already-cached list, to skip the loading state:
|
|
196
|
+
* ```svelte
|
|
197
|
+
* <script lang="ts">
|
|
198
|
+
* import { createQuery, useQueryClient } from '@tanstack/svelte-query'
|
|
199
|
+
*
|
|
200
|
+
* let { postId }: { postId: number } = $props()
|
|
201
|
+
*
|
|
202
|
+
* const queryClient = useQueryClient()
|
|
203
|
+
*
|
|
204
|
+
* const query = createQuery(() => ({
|
|
205
|
+
* queryKey: ['post', postId],
|
|
206
|
+
* queryFn: () => fetchPost(postId),
|
|
207
|
+
* initialData: () =>
|
|
208
|
+
* queryClient
|
|
209
|
+
* .getQueryData<Array<Post>>(['posts'])
|
|
210
|
+
* ?.find((post) => post.id === postId),
|
|
211
|
+
* }))
|
|
212
|
+
* </script>
|
|
213
|
+
*
|
|
214
|
+
* {#if query.isError}
|
|
215
|
+
* <span>Error: {query.error.message}</span>
|
|
216
|
+
* {/if}
|
|
217
|
+
* <h1>{query.data?.title}</h1>
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* Paginated data, keeping the previous page's data visible while the next page loads:
|
|
222
|
+
* ```svelte
|
|
223
|
+
* <script lang="ts">
|
|
224
|
+
* import { createQuery, keepPreviousData } from '@tanstack/svelte-query'
|
|
225
|
+
*
|
|
226
|
+
* let page = $state(0)
|
|
227
|
+
*
|
|
228
|
+
* const query = createQuery(() => ({
|
|
229
|
+
* queryKey: ['posts', page],
|
|
230
|
+
* queryFn: () => fetchPosts(page),
|
|
231
|
+
* placeholderData: keepPreviousData,
|
|
232
|
+
* }))
|
|
233
|
+
* </script>
|
|
234
|
+
*
|
|
235
|
+
* {#if query.isError}
|
|
236
|
+
* <span>Error: {query.error.message}</span>
|
|
237
|
+
* {/if}
|
|
238
|
+
* <ul>
|
|
239
|
+
* {#each query.data ?? [] as post (post.id)}
|
|
240
|
+
* <li>{post.title}</li>
|
|
241
|
+
* {/each}
|
|
242
|
+
* </ul>
|
|
243
|
+
* <button disabled={query.isPlaceholderData} onclick={() => page++}>
|
|
244
|
+
* Next Page
|
|
245
|
+
* </button>
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
39
248
|
export function createQuery<
|
|
40
249
|
TQueryFnData,
|
|
41
250
|
TError = DefaultError,
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,10 @@ export type {
|
|
|
16
16
|
export { queryOptions } from './queryOptions.js'
|
|
17
17
|
export { createQueries } from './createQueries.svelte.js'
|
|
18
18
|
export { createInfiniteQuery } from './createInfiniteQuery.js'
|
|
19
|
+
export type {
|
|
20
|
+
DefinedInitialDataInfiniteOptions,
|
|
21
|
+
UndefinedInitialDataInfiniteOptions,
|
|
22
|
+
} from './infiniteQueryOptions.js'
|
|
19
23
|
export { infiniteQueryOptions } from './infiniteQueryOptions.js'
|
|
20
24
|
export { mutationOptions } from './mutationOptions.js'
|
|
21
25
|
export { createMutation } from './createMutation.svelte.js'
|
|
@@ -1,6 +1,94 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
DefaultError,
|
|
3
|
+
InfiniteData,
|
|
4
|
+
InitialDataFunction,
|
|
5
|
+
NonUndefinedGuard,
|
|
6
|
+
QueryKey,
|
|
7
|
+
QueryKeyWithDataTag,
|
|
8
|
+
} from '@tanstack/query-core'
|
|
2
9
|
import type { CreateInfiniteQueryOptions } from './types.js'
|
|
3
10
|
|
|
11
|
+
export type UndefinedInitialDataInfiniteOptions<
|
|
12
|
+
TQueryFnData = unknown,
|
|
13
|
+
TError = DefaultError,
|
|
14
|
+
TData = InfiniteData<TQueryFnData>,
|
|
15
|
+
TQueryKey extends QueryKey = QueryKey,
|
|
16
|
+
TPageParam = unknown,
|
|
17
|
+
> = CreateInfiniteQueryOptions<
|
|
18
|
+
TQueryFnData,
|
|
19
|
+
TError,
|
|
20
|
+
TData,
|
|
21
|
+
TQueryKey,
|
|
22
|
+
TPageParam
|
|
23
|
+
> & {
|
|
24
|
+
initialData?:
|
|
25
|
+
| undefined
|
|
26
|
+
| NonUndefinedGuard<InfiniteData<TQueryFnData, TPageParam>>
|
|
27
|
+
| InitialDataFunction<
|
|
28
|
+
NonUndefinedGuard<InfiniteData<TQueryFnData, TPageParam>>
|
|
29
|
+
>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type DefinedInitialDataInfiniteOptions<
|
|
33
|
+
TQueryFnData = unknown,
|
|
34
|
+
TError = DefaultError,
|
|
35
|
+
TData = InfiniteData<TQueryFnData>,
|
|
36
|
+
TQueryKey extends QueryKey = QueryKey,
|
|
37
|
+
TPageParam = unknown,
|
|
38
|
+
> = CreateInfiniteQueryOptions<
|
|
39
|
+
TQueryFnData,
|
|
40
|
+
TError,
|
|
41
|
+
TData,
|
|
42
|
+
TQueryKey,
|
|
43
|
+
TPageParam
|
|
44
|
+
> & {
|
|
45
|
+
initialData:
|
|
46
|
+
| NonUndefinedGuard<InfiniteData<TQueryFnData, TPageParam>>
|
|
47
|
+
| (() => NonUndefinedGuard<InfiniteData<TQueryFnData, TPageParam>>)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* You can generally pass everything to `infiniteQueryOptions` that you can also pass to `createInfiniteQuery`.
|
|
52
|
+
* These options can be shared across `createInfiniteQuery` calls and imperative APIs such as
|
|
53
|
+
* `queryClient.infiniteQuery`. `options.queryKey` is required and is the query key to generate options for.
|
|
54
|
+
*
|
|
55
|
+
* This overload is selected when `initialData` is set.
|
|
56
|
+
*
|
|
57
|
+
* @see {@link createInfiniteQuery} to run an infinite query with these options.
|
|
58
|
+
* @param options - The {@link DefinedInitialDataInfiniteOptions} to use — everything you can pass to
|
|
59
|
+
* `createInfiniteQuery`, with `initialData` set.
|
|
60
|
+
* @returns The same options object, typed so that `queryKey` carries the inferred data type.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* `initialData` skips the loading state on first render — even if a refetch fails, the list stays
|
|
64
|
+
* visible alongside the error:
|
|
65
|
+
* ```svelte
|
|
66
|
+
* <script lang="ts">
|
|
67
|
+
* import { infiniteQueryOptions, createInfiniteQuery } from '@tanstack/svelte-query'
|
|
68
|
+
*
|
|
69
|
+
* const projectsOptions = infiniteQueryOptions({
|
|
70
|
+
* queryKey: ['projects'],
|
|
71
|
+
* queryFn: ({ pageParam }) => fetchProjects(pageParam),
|
|
72
|
+
* initialPageParam: 0,
|
|
73
|
+
* getNextPageParam: (lastPage) => lastPage.nextId,
|
|
74
|
+
* initialData: { pages: [], pageParams: [] },
|
|
75
|
+
* })
|
|
76
|
+
*
|
|
77
|
+
* const query = createInfiniteQuery(() => projectsOptions)
|
|
78
|
+
* </script>
|
|
79
|
+
*
|
|
80
|
+
* {#if query.isError}
|
|
81
|
+
* <span>Error: {query.error.message}</span>
|
|
82
|
+
* {/if}
|
|
83
|
+
* <ul>
|
|
84
|
+
* {#each query.data.pages as page}
|
|
85
|
+
* {#each page.projects as project (project.id)}
|
|
86
|
+
* <li>{project.name}</li>
|
|
87
|
+
* {/each}
|
|
88
|
+
* {/each}
|
|
89
|
+
* </ul>
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
4
92
|
export function infiniteQueryOptions<
|
|
5
93
|
TQueryFnData,
|
|
6
94
|
TError = DefaultError,
|
|
@@ -8,19 +96,89 @@ export function infiniteQueryOptions<
|
|
|
8
96
|
TQueryKey extends QueryKey = QueryKey,
|
|
9
97
|
TPageParam = unknown,
|
|
10
98
|
>(
|
|
11
|
-
options:
|
|
99
|
+
options: DefinedInitialDataInfiniteOptions<
|
|
12
100
|
TQueryFnData,
|
|
13
101
|
TError,
|
|
14
102
|
TData,
|
|
15
103
|
TQueryKey,
|
|
16
104
|
TPageParam
|
|
17
105
|
>,
|
|
18
|
-
):
|
|
106
|
+
): DefinedInitialDataInfiniteOptions<
|
|
19
107
|
TQueryFnData,
|
|
20
108
|
TError,
|
|
21
109
|
TData,
|
|
22
110
|
TQueryKey,
|
|
23
111
|
TPageParam
|
|
24
|
-
>
|
|
112
|
+
> &
|
|
113
|
+
QueryKeyWithDataTag<TQueryKey, InfiniteData<TQueryFnData>, TError>
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* You can generally pass everything to `infiniteQueryOptions` that you can also pass to `createInfiniteQuery`.
|
|
117
|
+
* These options can be shared across `createInfiniteQuery` calls and imperative APIs such as
|
|
118
|
+
* `queryClient.infiniteQuery`. `options.queryKey` is required and is the query key to generate options for.
|
|
119
|
+
*
|
|
120
|
+
* @see {@link createInfiniteQuery} to run an infinite query with these options.
|
|
121
|
+
* @param options - The {@link UndefinedInitialDataInfiniteOptions} to use — everything you can pass to
|
|
122
|
+
* `createInfiniteQuery`.
|
|
123
|
+
* @returns The same options object, typed so that `queryKey` carries the inferred data type.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* A parameterized factory, so the same options object can be reused per `postId`:
|
|
127
|
+
* ```svelte
|
|
128
|
+
* <script lang="ts">
|
|
129
|
+
* import { infiniteQueryOptions, createInfiniteQuery } from '@tanstack/svelte-query'
|
|
130
|
+
*
|
|
131
|
+
* let { postId }: { postId: string } = $props()
|
|
132
|
+
*
|
|
133
|
+
* const commentsOptions = (postId: string) =>
|
|
134
|
+
* infiniteQueryOptions({
|
|
135
|
+
* queryKey: ['post', postId, 'comments'],
|
|
136
|
+
* queryFn: ({ pageParam }) => fetchComments(postId, pageParam),
|
|
137
|
+
* initialPageParam: 0,
|
|
138
|
+
* getNextPageParam: (lastPage) => lastPage.nextId,
|
|
139
|
+
* })
|
|
140
|
+
*
|
|
141
|
+
* const query = createInfiniteQuery(() => commentsOptions(postId))
|
|
142
|
+
* </script>
|
|
143
|
+
*
|
|
144
|
+
* {#if query.isPending}
|
|
145
|
+
* Loading...
|
|
146
|
+
* {:else if query.isError}
|
|
147
|
+
* <span>Error: {query.error.message}</span>
|
|
148
|
+
* {:else}
|
|
149
|
+
* <ul>
|
|
150
|
+
* {#each query.data.pages as page}
|
|
151
|
+
* {#each page.comments as comment (comment.id)}
|
|
152
|
+
* <li>{comment.text}</li>
|
|
153
|
+
* {/each}
|
|
154
|
+
* {/each}
|
|
155
|
+
* </ul>
|
|
156
|
+
* {/if}
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function infiniteQueryOptions<
|
|
160
|
+
TQueryFnData,
|
|
161
|
+
TError = DefaultError,
|
|
162
|
+
TData = InfiniteData<TQueryFnData>,
|
|
163
|
+
TQueryKey extends QueryKey = QueryKey,
|
|
164
|
+
TPageParam = unknown,
|
|
165
|
+
>(
|
|
166
|
+
options: UndefinedInitialDataInfiniteOptions<
|
|
167
|
+
TQueryFnData,
|
|
168
|
+
TError,
|
|
169
|
+
TData,
|
|
170
|
+
TQueryKey,
|
|
171
|
+
TPageParam
|
|
172
|
+
>,
|
|
173
|
+
): UndefinedInitialDataInfiniteOptions<
|
|
174
|
+
TQueryFnData,
|
|
175
|
+
TError,
|
|
176
|
+
TData,
|
|
177
|
+
TQueryKey,
|
|
178
|
+
TPageParam
|
|
179
|
+
> &
|
|
180
|
+
QueryKeyWithDataTag<TQueryKey, InfiniteData<TQueryFnData>, TError>
|
|
181
|
+
|
|
182
|
+
export function infiniteQueryOptions(options: unknown) {
|
|
25
183
|
return options
|
|
26
184
|
}
|