@kubb/plugin-react-query 5.10.2 → 5.10.4
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/index.cjs +2 -2
- package/dist/index.js +2 -2
- package/docs/guides/calling-operations.md +44 -108
- package/docs/guides/infinite-queries.md +86 -0
- package/docs/guides/query-keys.md +104 -0
- package/docs/options.md +205 -192
- package/docs/overview.md +18 -14
- package/kubb-extension.json +2 -2
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -33,11 +33,11 @@ let node_fs = require("node:fs");
|
|
|
33
33
|
node_fs = __toESM(node_fs, 1);
|
|
34
34
|
// kubb-extension.json
|
|
35
35
|
var compatibility = {
|
|
36
|
-
"kubb": ">=5.
|
|
36
|
+
"kubb": ">=5.19.0",
|
|
37
37
|
"node": ">=22.22"
|
|
38
38
|
};
|
|
39
39
|
// package.json
|
|
40
|
-
var version = "5.10.
|
|
40
|
+
var version = "5.10.4";
|
|
41
41
|
// ../../internals/client/src/resolveClient.ts
|
|
42
42
|
/**
|
|
43
43
|
* Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,11 @@ import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
// kubb-extension.json
|
|
8
8
|
var compatibility = {
|
|
9
|
-
"kubb": ">=5.
|
|
9
|
+
"kubb": ">=5.19.0",
|
|
10
10
|
"node": ">=22.22"
|
|
11
11
|
};
|
|
12
12
|
// package.json
|
|
13
|
-
var version = "5.10.
|
|
13
|
+
var version = "5.10.4";
|
|
14
14
|
// ../../internals/client/src/resolveClient.ts
|
|
15
15
|
/**
|
|
16
16
|
* Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
|
|
@@ -1,62 +1,49 @@
|
|
|
1
1
|
# Call operations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use the generated TanStack Query hooks and factories in React: queries, mutations, infinite lists, and suspense.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
> By default the plugin emits only the factory helpers (`queryOptions`, `mutationOptions`, `queryKey`, `mutationKey`). Set [`hooks: true`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#hooks) in the plugin options to also generate the `use*` hooks shown below.
|
|
5
|
+
## What each plugin generates
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
Each hook and its helpers live in a file named after the hook, such as `src/gen/hooks/useGetPetById.ts`.
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
| Operation | Exports |
|
|
10
|
+
| ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| Query (`GET`, `QUERY`) | `getPetByIdQueryKey`, `getPetByIdQueryOptions`, plus `useGetPetById` with `hooks` |
|
|
12
|
+
| Mutation (`POST`, `PUT`, `PATCH`, `DELETE`) | `updatePetMutationKey`, `updatePetMutationOptions`, plus `useUpdatePet` with `hooks` |
|
|
13
|
+
| Infinite, with `infinite` and `hooks` | `findPetsByTagsInfiniteQueryKey`, `findPetsByTagsInfiniteQueryOptions`, `useFindPetsByTagsInfinite` |
|
|
14
|
+
| Suspense, with `suspense` and `hooks` | `useGetPetByIdSuspense`, plus `useFindPetsByTagsSuspenseInfinite` with `infinite` |
|
|
15
|
+
| Server-Sent Events or JSON Lines | Nothing. Call the client function directly. |
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
import { useGetPetById } from './gen/hooks/useGetPetById'
|
|
17
|
+
## Call a hook
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
```
|
|
19
|
+
The examples set `hooks: true`, and [`integerType: 'number'`](https://kubb.dev/extensions/kubb-labs/adapter-oas/options#integertype) on the adapter so `petId` is a `number`. Path keys keep their spec names unless you set [`pathParamsCasing`](https://kubb.dev/extensions/kubb-labs/adapter-oas/options#pathparamscasing).
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
::tabs
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
:::tabs-item{label="Query"}
|
|
21
24
|
|
|
22
|
-
The
|
|
25
|
+
The first argument takes the request groups: `path`, `query`, `headers`. The second takes TanStack Query options in `query`, with `query.client` for the `QueryClient`, and request config such as `baseURL` or `signal` in `client`.
|
|
23
26
|
|
|
24
27
|
```typescript
|
|
25
28
|
import { useGetPetById } from './gen/hooks/useGetPetById'
|
|
26
29
|
|
|
27
|
-
useGetPetById(
|
|
30
|
+
const { data, error, isLoading } = useGetPetById(
|
|
28
31
|
{ path: { petId: 1 } },
|
|
29
|
-
{
|
|
30
|
-
query: { staleTime: 60_000 },
|
|
31
|
-
client: { baseURL: 'https://api.example.com/v1' },
|
|
32
|
-
},
|
|
32
|
+
{ query: { staleTime: 60_000 }, client: { baseURL: 'https://api.example.com/v1' } },
|
|
33
33
|
)
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Each query operation also exports a `queryOptions` factory and a `queryKey` helper. Use them to prefetch or invalidate a query outside a hook. The key includes the operation URL and path parameters, followed by query or body values when present:
|
|
39
|
-
|
|
40
|
-
```typescript
|
|
41
|
-
import { useQueryClient } from '@tanstack/react-query'
|
|
42
|
-
import { getPetByIdQueryKey, getPetByIdQueryOptions } from './gen/hooks/useGetPetById'
|
|
43
|
-
|
|
44
|
-
const queryClient = useQueryClient()
|
|
45
|
-
|
|
46
|
-
await queryClient.prefetchQuery(getPetByIdQueryOptions({ path: { petId: 1 } }))
|
|
47
|
-
queryClient.invalidateQueries({ queryKey: getPetByIdQueryKey({ path: { petId: 1 } }) })
|
|
48
|
-
```
|
|
36
|
+
:::
|
|
49
37
|
|
|
50
|
-
|
|
38
|
+
:::tabs-item{label="Mutation"}
|
|
51
39
|
|
|
52
|
-
A mutation hook takes only
|
|
40
|
+
A mutation hook takes only the options object, with `mutation` and `client`. Pass the request groups to `mutate` or `mutateAsync`.
|
|
53
41
|
|
|
54
42
|
```typescript
|
|
55
43
|
import { useQueryClient } from '@tanstack/react-query'
|
|
56
44
|
import { useDeletePet } from './gen/hooks/useDeletePet'
|
|
57
45
|
|
|
58
46
|
const queryClient = useQueryClient()
|
|
59
|
-
|
|
60
47
|
const { mutate } = useDeletePet({
|
|
61
48
|
mutation: { onSuccess: () => queryClient.invalidateQueries() },
|
|
62
49
|
})
|
|
@@ -64,108 +51,57 @@ const { mutate } = useDeletePet({
|
|
|
64
51
|
mutate({ path: { petId: 1 } })
|
|
65
52
|
```
|
|
66
53
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
## Errors and transport
|
|
70
|
-
|
|
71
|
-
Each generated hook calls the client function with `throwOnError: true`. A failed request sets TanStack Query's `error`, typed from the error responses in the spec. Set the base URL, authentication, interceptors, serialization, and validation on the client plugin. See the [plugin-fetch](https://kubb.dev/extensions/kubb-labs/plugin-fetch) or [plugin-axios](https://kubb.dev/extensions/kubb-labs/plugin-axios) guide. With [plugin-client](https://kubb.dev/extensions/kubb-labs/plugin-client), set these in your own client module.
|
|
72
|
-
|
|
73
|
-
## Customize cache keys
|
|
74
|
-
|
|
75
|
-
Set `queryKey` on the plugin to change generated keys. String entries are emitted as source code, so use `JSON.stringify` for a string literal.
|
|
76
|
-
|
|
77
|
-
```typescript [kubb.config.ts]
|
|
78
|
-
import { pluginReactQuery } from '@kubb/plugin-react-query'
|
|
79
|
-
|
|
80
|
-
pluginReactQuery({
|
|
81
|
-
queryKey: ({ node }) => [JSON.stringify(node.operationId)],
|
|
82
|
-
})
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
> [!WARNING]
|
|
86
|
-
> This `queryKey` gives every call the same key, such as `['getUserByName']`. If path or query values select different data, add them to the key.
|
|
87
|
-
|
|
88
|
-
## Load more pages
|
|
54
|
+
:::
|
|
89
55
|
|
|
90
|
-
|
|
56
|
+
:::tabs-item{label="Infinite"}
|
|
91
57
|
|
|
92
|
-
|
|
58
|
+
Only operations that declare `infinite.queryParam` get an infinite hook. Point `nextParam` at the cursor in the response, and give `initialPageParam` the type of the query parameter. See [Infinite queries](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/infinite-queries).
|
|
93
59
|
|
|
94
60
|
```typescript [kubb.config.ts]
|
|
95
|
-
import { pluginReactQuery } from '@kubb/plugin-react-query'
|
|
96
|
-
|
|
97
61
|
pluginReactQuery({
|
|
98
62
|
hooks: true,
|
|
99
|
-
infinite: {
|
|
100
|
-
queryParam: 'page',
|
|
101
|
-
initialPageParam: 0,
|
|
102
|
-
nextParam: 'pagination.next.cursor',
|
|
103
|
-
},
|
|
63
|
+
infinite: { queryParam: 'page', initialPageParam: 0, nextParam: 'pagination.next.cursor' },
|
|
104
64
|
})
|
|
105
65
|
```
|
|
106
66
|
|
|
107
|
-
```typescript
|
|
108
|
-
import {
|
|
109
|
-
import { findPetsByTagsInfiniteQueryOptions } from './gen/hooks/useFindPetsByTagsInfinite'
|
|
67
|
+
```typescript
|
|
68
|
+
import { useFindPetsByTagsInfinite } from './gen/hooks/useFindPetsByTagsInfinite'
|
|
110
69
|
|
|
111
|
-
const { data, fetchNextPage, hasNextPage } =
|
|
112
|
-
findPetsByTagsInfiniteQueryOptions({ query: { tags: ['dog'] } }),
|
|
113
|
-
)
|
|
70
|
+
const { data, fetchNextPage, hasNextPage } = useFindPetsByTagsInfinite({ query: { tags: ['dog'] } })
|
|
114
71
|
```
|
|
115
72
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
`nextParam` takes dot notation or an array of keys. Change it to match your API's response, and give `initialPageParam` the same type as the query parameter. Without `getNextPageParam`, `nextParam` or `cursorParam`, the generated options increment the page number until a page returns an empty array.
|
|
119
|
-
|
|
120
|
-
## Use suspense
|
|
73
|
+
:::
|
|
121
74
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
::code-group
|
|
125
|
-
|
|
126
|
-
```typescript [kubb.config.ts]
|
|
127
|
-
import { pluginReactQuery } from '@kubb/plugin-react-query'
|
|
75
|
+
:::tabs-item{label="Suspense"}
|
|
128
76
|
|
|
129
|
-
|
|
130
|
-
```
|
|
77
|
+
Set `suspense: {}` next to `hooks: true`. A suspense hook takes the same arguments as the query hook.
|
|
131
78
|
|
|
132
|
-
```typescript
|
|
79
|
+
```typescript
|
|
133
80
|
import { useGetPetByIdSuspense } from './gen/hooks/useGetPetByIdSuspense'
|
|
134
81
|
|
|
135
82
|
const { data } = useGetPetByIdSuspense({ path: { petId: 1 } })
|
|
136
83
|
```
|
|
137
84
|
|
|
85
|
+
:::
|
|
86
|
+
|
|
138
87
|
::
|
|
139
88
|
|
|
140
|
-
##
|
|
89
|
+
## Prefetch and invalidate
|
|
141
90
|
|
|
142
|
-
|
|
91
|
+
The factories work without `hooks`, so you can prefetch or invalidate outside a component:
|
|
143
92
|
|
|
144
|
-
```typescript
|
|
145
|
-
import {
|
|
93
|
+
```typescript
|
|
94
|
+
import { getPetByIdQueryKey, getPetByIdQueryOptions } from './gen/hooks/useGetPetById'
|
|
95
|
+
import { queryClient } from './queryClient' // the QueryClient you pass to QueryClientProvider
|
|
146
96
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
customOptions: {
|
|
150
|
-
importPath: './useCustomHookOptions',
|
|
151
|
-
name: 'useCustomHookOptions',
|
|
152
|
-
},
|
|
153
|
-
})
|
|
97
|
+
await queryClient.prefetchQuery(getPetByIdQueryOptions({ path: { petId: 1 } }))
|
|
98
|
+
queryClient.invalidateQueries({ queryKey: getPetByIdQueryKey({ path: { petId: 1 } }) })
|
|
154
99
|
```
|
|
155
100
|
|
|
156
|
-
|
|
101
|
+
[TanStack Query keys](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/query-keys) shows the default keys. To change them, set [`queryKey`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#querykey) and [`mutationKey`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#mutationkey). To share options across hooks, set [`customOptions`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#customoptions).
|
|
157
102
|
|
|
158
|
-
|
|
159
|
-
import type { HookOptions } from './HookOptions'
|
|
103
|
+
## Handle errors
|
|
160
104
|
|
|
161
|
-
|
|
162
|
-
{ hookName }: { hookName: keyof HookOptions; operationId: string },
|
|
163
|
-
) {
|
|
164
|
-
if (hookName === 'useGetPetById') {
|
|
165
|
-
return { staleTime: 60_000 } satisfies HookOptions['useGetPetById']
|
|
166
|
-
}
|
|
167
|
-
return {}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
105
|
+
Each hook calls the client with `throwOnError: true`, so a failed request sets TanStack Query's `error`, typed from the spec's error responses.
|
|
170
106
|
|
|
171
|
-
|
|
107
|
+
Next, set the base URL, auth, and interceptors on your client plugin: [plugin-fetch](https://kubb.dev/extensions/kubb-labs/plugin-fetch), [plugin-axios](https://kubb.dev/extensions/kubb-labs/plugin-axios), or your own module with [plugin-client](https://kubb.dev/extensions/kubb-labs/plugin-client/guides/write-your-client).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Infinite queries with useInfiniteQuery
|
|
2
|
+
|
|
3
|
+
Generate `useInfiniteQuery` hooks for paginated endpoints, read the next cursor from the response, and stop once the last page arrives.
|
|
4
|
+
|
|
5
|
+
## Generate infinite hooks
|
|
6
|
+
|
|
7
|
+
When an endpoint pages through results with a query parameter, set [`infinite`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#infinite) next to `hooks: true`. Only operations that declare `infinite.queryParam` get an infinite hook, and the hook sends each page param as that parameter:
|
|
8
|
+
|
|
9
|
+
::code-group
|
|
10
|
+
|
|
11
|
+
```typescript [kubb.config.ts]
|
|
12
|
+
import { defineConfig } from 'kubb/config'
|
|
13
|
+
import { pluginTs } from '@kubb/plugin-ts'
|
|
14
|
+
import { pluginFetch } from '@kubb/plugin-fetch'
|
|
15
|
+
import { pluginReactQuery } from '@kubb/plugin-react-query'
|
|
16
|
+
|
|
17
|
+
export default defineConfig({
|
|
18
|
+
input: './petStore.yaml',
|
|
19
|
+
output: { path: './src/gen' },
|
|
20
|
+
plugins: [
|
|
21
|
+
pluginTs(),
|
|
22
|
+
pluginFetch(),
|
|
23
|
+
pluginReactQuery({
|
|
24
|
+
hooks: true,
|
|
25
|
+
infinite: { queryParam: 'page', initialPageParam: 0, nextParam: 'pagination.next.cursor' },
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```typescript [Generated]
|
|
32
|
+
// src/gen/hooks/useFindPetsByTagsInfinite.ts, types left out
|
|
33
|
+
export const findPetsByTagsInfiniteQueryKey = ({ query }: Omit<FindPetsByTagsOptions, 'headers'> = {}) =>
|
|
34
|
+
[{ url: '/pet/findByTags', infinite: true }, ...(query ? [query] : [])] as const
|
|
35
|
+
|
|
36
|
+
export function findPetsByTagsInfiniteQueryOptions({ query }: FindPetsByTagsOptions = {}, config = {}) {
|
|
37
|
+
const queryKey = findPetsByTagsInfiniteQueryKey({ query })
|
|
38
|
+
return infiniteQueryOptions({
|
|
39
|
+
queryKey,
|
|
40
|
+
queryFn: async ({ signal, pageParam }) => {
|
|
41
|
+
return findPetsByTags({ ...config, query: { ...query, page: pageParam }, signal: config.signal ?? signal, throwOnError: true }).unwrap()
|
|
42
|
+
},
|
|
43
|
+
initialPageParam: 0,
|
|
44
|
+
getNextPageParam: (lastPage) => lastPage?.['pagination']?.['next']?.['cursor'],
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```typescript [Usage]
|
|
50
|
+
import { useFindPetsByTagsInfinite } from './gen/hooks/useFindPetsByTagsInfinite'
|
|
51
|
+
|
|
52
|
+
const { data, fetchNextPage, hasNextPage } = useFindPetsByTagsInfinite({ query: { tags: ['dog'] } })
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
::
|
|
56
|
+
|
|
57
|
+
- Give `initialPageParam` the type of the query parameter.
|
|
58
|
+
- The infinite key adds `infinite: true`, so it never shares a cache entry with the plain query. See [TanStack Query keys](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/query-keys).
|
|
59
|
+
- Set [`suspense: {}`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#suspense) as well to get `useFindPetsByTagsSuspenseInfinite`.
|
|
60
|
+
|
|
61
|
+
## Read the next page from the response
|
|
62
|
+
|
|
63
|
+
The generated `getNextPageParam` comes from the first of these options you set:
|
|
64
|
+
|
|
65
|
+
| Option | Generated `getNextPageParam` |
|
|
66
|
+
| --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
67
|
+
| [`getNextPageParam`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#infinitegetnextpageparam) | Your function's source, copied as written. It cannot use variables from the config file. |
|
|
68
|
+
| [`nextParam`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#infinitenextparam) | Reads that path on the last page, such as `lastPage?.['pagination']?.['next']?.['cursor']`. |
|
|
69
|
+
| [`cursorParam`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#infinitecursorparam) | Deprecated. Reads that top-level field. |
|
|
70
|
+
| None | Counts pages up from `initialPageParam` until a page is an empty array. |
|
|
71
|
+
|
|
72
|
+
`getPreviousPageParam`, `previousParam`, and `cursorParam` set the previous page in the same order. With [`returnType: 'full'`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#returntype), the `nextParam` and `cursorParam` accessors read from `lastPage.data`.
|
|
73
|
+
|
|
74
|
+
## hasNextPage never turns false
|
|
75
|
+
|
|
76
|
+
Generation prints this warning for the operation:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
findPetsByTags: the default infinite page params expect an array response and never end for this one. Set `infinite.getNextPageParam` (or `nextParam`) to read the next page from the response.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Without `getNextPageParam`, `nextParam`, or `cursorParam`, the hook counts pages up from `initialPageParam` until a page is an empty array. That works only for array responses, so generation warns for any other response. It skips the warning when `previousParam` or `getPreviousPageParam` is set, though the count still never ends.
|
|
83
|
+
|
|
84
|
+
To fix it, set `nextParam` to the cursor path, or `getNextPageParam` when you must compute the next page.
|
|
85
|
+
|
|
86
|
+
Next, see every [`infinite` option](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#infinite), including `definePageParam` for a typed `getNextPageParam`.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# TanStack Query keys
|
|
2
|
+
|
|
3
|
+
See the query key each generated React Query hook uses, invalidate or read the cache with it, and add your own prefix to the default key.
|
|
4
|
+
|
|
5
|
+
## The default query key
|
|
6
|
+
|
|
7
|
+
When you call `invalidateQueries`, `getQueryData`, or `setQueryData`, take the key from the `<operation>QueryKey` helper in each hook file. It builds `[{ url, params }, query, body]`:
|
|
8
|
+
|
|
9
|
+
::code-group
|
|
10
|
+
|
|
11
|
+
```typescript [Generated]
|
|
12
|
+
// src/gen/hooks/useGetPetById.ts
|
|
13
|
+
export const getPetByIdQueryKey = ({ path }: Omit<GetPetByIdOptions, 'headers'>) => [{ url: '/pet/:petId', params: path }] as const
|
|
14
|
+
|
|
15
|
+
// src/gen/hooks/useFindPetsByTags.ts
|
|
16
|
+
export const findPetsByTagsQueryKey = ({ query }: Omit<FindPetsByTagsOptions, 'headers'> = {}) =>
|
|
17
|
+
[{ url: '/pet/findByTags' }, ...(query ? [query] : [])] as const
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```typescript [Usage]
|
|
21
|
+
import { getPetByIdQueryKey } from './gen/hooks/useGetPetById'
|
|
22
|
+
import { findPetsByTagsQueryKey } from './gen/hooks/useFindPetsByTags'
|
|
23
|
+
import { queryClient } from './queryClient'
|
|
24
|
+
|
|
25
|
+
getPetByIdQueryKey({ path: { petId: 1 } }) // [{ url: '/pet/:petId', params: { petId: 1 } }]
|
|
26
|
+
findPetsByTagsQueryKey({ query: { tags: ['dog'] } }) // [{ url: '/pet/findByTags' }, { tags: ['dog'] }]
|
|
27
|
+
|
|
28
|
+
const pet = queryClient.getQueryData(getPetByIdQueryKey({ path: { petId: 1 } }))
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
::
|
|
32
|
+
|
|
33
|
+
- `url` is the spec path with `:name` placeholders, such as `'/pet/:petId'`.
|
|
34
|
+
- `params` holds the path parameters, when the path has any.
|
|
35
|
+
- `query` and `body` follow when the operation has them and the call passes them.
|
|
36
|
+
- Headers and cookies stay out of the key.
|
|
37
|
+
- Infinite variants add `infinite: true` to the first entry, so they never share a cache entry with the plain query.
|
|
38
|
+
- Each hook returns the key it used as `queryKey` on its result.
|
|
39
|
+
|
|
40
|
+
## Invalidate every call of an operation
|
|
41
|
+
|
|
42
|
+
TanStack Query matches a key by its prefix, and an object entry by the fields you pass. A key built without `query` matches every cached call of that operation with the same path parameters, infinite ones included:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
queryClient.invalidateQueries({ queryKey: findPetsByTagsQueryKey() })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Mutation keys
|
|
49
|
+
|
|
50
|
+
Each mutation gets a `<operation>MutationKey` helper that returns `[{ url }]`, for filters such as `useIsMutating` or `useMutationState`:
|
|
51
|
+
|
|
52
|
+
::code-group
|
|
53
|
+
|
|
54
|
+
```typescript [Generated]
|
|
55
|
+
// src/gen/hooks/useUpdatePet.ts
|
|
56
|
+
export const updatePetMutationKey = () => [{ url: '/pet' }] as const
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```typescript [Usage]
|
|
60
|
+
import { useIsMutating } from '@tanstack/react-query'
|
|
61
|
+
import { updatePetMutationKey } from './gen/hooks/useUpdatePet'
|
|
62
|
+
|
|
63
|
+
const saving = useIsMutating({ mutationKey: updatePetMutationKey() })
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
::
|
|
67
|
+
|
|
68
|
+
## Extend the default key
|
|
69
|
+
|
|
70
|
+
When you need your own entry, such as an API version, set [`queryKey`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#querykey) and spread `queryKeyTransformer`. Do not read single entries of its result: they can change between releases.
|
|
71
|
+
|
|
72
|
+
> [!WARNING]
|
|
73
|
+
> Returned strings are copied into the generated code as written. Wrap a string literal in `JSON.stringify(...)`.
|
|
74
|
+
|
|
75
|
+
::code-group
|
|
76
|
+
|
|
77
|
+
```typescript [kubb.config.ts]
|
|
78
|
+
import { defineConfig } from 'kubb/config'
|
|
79
|
+
import { pluginTs } from '@kubb/plugin-ts'
|
|
80
|
+
import { pluginFetch } from '@kubb/plugin-fetch'
|
|
81
|
+
import { pluginReactQuery, queryKeyTransformer } from '@kubb/plugin-react-query'
|
|
82
|
+
|
|
83
|
+
export default defineConfig({
|
|
84
|
+
input: './petStore.yaml',
|
|
85
|
+
output: { path: './src/gen' },
|
|
86
|
+
plugins: [
|
|
87
|
+
pluginTs(),
|
|
88
|
+
pluginFetch(),
|
|
89
|
+
pluginReactQuery({
|
|
90
|
+
queryKey: (props) => [JSON.stringify('v2'), ...queryKeyTransformer(props)],
|
|
91
|
+
}),
|
|
92
|
+
],
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```typescript [Generated]
|
|
97
|
+
export const getPetByIdQueryKey = ({ path }: Omit<GetPetByIdOptions, 'headers'>) => ["v2", { url: '/pet/:petId', params: path }] as const
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
::
|
|
101
|
+
|
|
102
|
+
The builder also gets the `variant`, so it can return a different key for suspense or infinite hooks. [`mutationKey`](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options#mutationkey) works the same way with `mutationKeyTransformer`.
|
|
103
|
+
|
|
104
|
+
Next, [generate infinite queries](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/infinite-queries) for paginated endpoints.
|
package/docs/options.md
CHANGED
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
# Options
|
|
2
2
|
|
|
3
|
-
Pass these options to `pluginReactQuery()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options)
|
|
3
|
+
Pass these options to `pluginReactQuery()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options).
|
|
4
4
|
|
|
5
5
|
## Options overview
|
|
6
6
|
|
|
7
|
-
| Option | Purpose
|
|
8
|
-
| ------------------------------------------------------------------------- |
|
|
9
|
-
| [`
|
|
10
|
-
| [`
|
|
11
|
-
| [`
|
|
12
|
-
| [`
|
|
13
|
-
| [`
|
|
14
|
-
| [`
|
|
15
|
-
| [`
|
|
16
|
-
| [`
|
|
17
|
-
| [`mutation`](#
|
|
18
|
-
| [`
|
|
19
|
-
| [`
|
|
20
|
-
| [`
|
|
21
|
-
| [`
|
|
22
|
-
| [`
|
|
23
|
-
| [`
|
|
24
|
-
| [`
|
|
25
|
-
| [`
|
|
7
|
+
| Option | Purpose | Default |
|
|
8
|
+
| ------------------------------------------------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
9
|
+
| [`client`](#client) | Client plugin the hooks call. | Auto-detected |
|
|
10
|
+
| [`returnType`](#returntype) | What the hooks resolve to. | `'data'` |
|
|
11
|
+
| [`hooks`](#hooks) | Emit `use*` hooks on top of the factories. | `false` |
|
|
12
|
+
| [`query`](#query) | Which methods become queries, and the TanStack import. | `{ methods: ['GET', 'QUERY'], importPath: '@tanstack/react-query' }` |
|
|
13
|
+
| [`query.methods`](#querymethods) | Methods that become queries. | `['GET', 'QUERY']` |
|
|
14
|
+
| [`query.importPath`](#queryimportpath) | Import path of the query helpers. | `'@tanstack/react-query'` |
|
|
15
|
+
| [`queryKey`](#querykey) | Build the `queryKey` of each query. | `queryKeyTransformer` |
|
|
16
|
+
| [`mutation`](#mutation) | Which methods become mutations, and the TanStack import. | `{ methods: ['POST', 'PUT', 'PATCH', 'DELETE'], importPath: '@tanstack/react-query' }` |
|
|
17
|
+
| [`mutation.methods`](#mutationmethods) | Methods that become mutations. | `['POST', 'PUT', 'PATCH', 'DELETE']` |
|
|
18
|
+
| [`mutation.importPath`](#mutationimportpath) | Import path of the mutation helpers. | `'@tanstack/react-query'` |
|
|
19
|
+
| [`mutationKey`](#mutationkey) | Build the `mutationKey` of each mutation. | `mutationKeyTransformer` |
|
|
20
|
+
| [`infinite`](#infinite) | Generate infinite queries for pagination. | `false` |
|
|
21
|
+
| [`infinite.queryParam`](#infinitequeryparam) | Query parameter for the page cursor. | `'id'` |
|
|
22
|
+
| [`infinite.initialPageParam`](#infiniteinitialpageparam) | First `pageParam`. | `0` |
|
|
23
|
+
| [`infinite.nextParam`](#infinitenextparam) | Path to the next cursor. | `null` |
|
|
24
|
+
| [`infinite.previousParam`](#infinitepreviousparam) | Path to the previous cursor. | `null` |
|
|
25
|
+
| [`infinite.getNextPageParam`](#infinitegetnextpageparam) | Compute the next page param. | `null` |
|
|
26
|
+
| [`infinite.getPreviousPageParam`](#infinitegetpreviouspageparam) | Compute the previous page param. | `null` |
|
|
27
|
+
| [`infinite.cursorParam`](#infinitecursorparam) | Deprecated cursor field. | `null` |
|
|
28
|
+
| [`suspense`](#suspense) | Generate `useSuspenseQuery` hooks. | `false` |
|
|
29
|
+
| [`customOptions`](#customoptions) | Route every hook through your own options function. | None |
|
|
30
|
+
| [`customOptions.importPath`](#customoptionsimportpath) | Module of your function. | None, required |
|
|
31
|
+
| [`customOptions.name`](#customoptionsname) | Name of your function. | `'useCustomHookOptions'` |
|
|
32
|
+
| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written. | `{ path: 'hooks', barrel: { type: 'named' } }` |
|
|
33
|
+
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path. | None |
|
|
34
|
+
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations that match. | None |
|
|
35
|
+
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations that match. | `[]` |
|
|
36
|
+
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
|
|
37
|
+
| [`resolver`](#resolver) | Customize generated names and file paths. | `resolverReactQuery` |
|
|
38
|
+
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]` |
|
|
26
39
|
|
|
27
40
|
## Option details
|
|
28
41
|
|
|
29
42
|
### client
|
|
30
43
|
|
|
31
|
-
|
|
44
|
+
The client plugin the hooks call. Kubb detects a lone client plugin, so set `client` only when several are registered. Generation fails when none is.
|
|
32
45
|
|
|
33
46
|
| | |
|
|
34
47
|
| -------- | -------------------------------- |
|
|
@@ -38,171 +51,62 @@ Selects which registered client plugin the hooks call. A single registered clien
|
|
|
38
51
|
::field-group
|
|
39
52
|
|
|
40
53
|
:::field{name="'fetch'"}
|
|
41
|
-
Calls
|
|
54
|
+
Calls [`@kubb/plugin-fetch`](https://kubb.dev/extensions/kubb-labs/plugin-fetch).
|
|
42
55
|
:::
|
|
43
56
|
|
|
44
57
|
:::field{name="'axios'"}
|
|
45
|
-
Calls
|
|
58
|
+
Calls [`@kubb/plugin-axios`](https://kubb.dev/extensions/kubb-labs/plugin-axios).
|
|
46
59
|
:::
|
|
47
60
|
|
|
48
61
|
:::field{name="'client'"}
|
|
49
|
-
Calls
|
|
62
|
+
Calls [`@kubb/plugin-client`](https://kubb.dev/extensions/kubb-labs/plugin-client). Your client module must also export `RequestConfig` and `ResponseErrorConfig`.
|
|
50
63
|
:::
|
|
51
64
|
|
|
52
65
|
::
|
|
53
66
|
|
|
54
67
|
### returnType
|
|
55
68
|
|
|
56
|
-
|
|
69
|
+
What the hooks resolve to.
|
|
57
70
|
|
|
58
71
|
| | |
|
|
59
72
|
| -------- | ------------------ |
|
|
60
|
-
| Type | `'
|
|
73
|
+
| Type | `'data' \| 'full'` |
|
|
61
74
|
| Required | `false` |
|
|
62
75
|
| Default | `'data'` |
|
|
63
76
|
|
|
64
77
|
::field-group
|
|
65
78
|
|
|
66
|
-
:::field{name="'
|
|
67
|
-
|
|
79
|
+
:::field{name="'data'"}
|
|
80
|
+
Resolves to the success body.
|
|
68
81
|
:::
|
|
69
82
|
|
|
70
|
-
:::field{name="'
|
|
71
|
-
|
|
83
|
+
:::field{name="'full'"}
|
|
84
|
+
Resolves to the client's whole `RequestResult`, so a hook can read the status and headers. Needs a client plugin with `returnType` `'full'` or `'plain'`, or generation fails.
|
|
72
85
|
:::
|
|
73
86
|
|
|
74
87
|
::
|
|
75
88
|
|
|
76
|
-
```
|
|
89
|
+
```typescript
|
|
77
90
|
pluginReactQuery({ returnType: 'full' })
|
|
78
91
|
|
|
92
|
+
// with integerType: 'number' on the adapter
|
|
79
93
|
const { data: result } = useGetPetById({ path: { petId: 1 } })
|
|
80
|
-
|
|
81
94
|
const etag = result?.response.headers.get('ETag')
|
|
82
|
-
const pet = result?.data
|
|
83
95
|
```
|
|
84
96
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
### infinite
|
|
88
|
-
|
|
89
|
-
Adds `infiniteQueryOptions` and `useInfiniteQuery` for operations that declare the query parameter named in `infinite.queryParam`. Needs [`hooks: true`](#hooks).
|
|
90
|
-
|
|
91
|
-
| | |
|
|
92
|
-
| -------- | ---------------------------- |
|
|
93
|
-
| Type | `Partial<Infinite> \| false` |
|
|
94
|
-
| Required | `false` |
|
|
95
|
-
| Default | `false` |
|
|
96
|
-
|
|
97
|
-
#### infinite.queryParam
|
|
98
|
-
|
|
99
|
-
Query parameter that carries the page cursor.
|
|
100
|
-
|
|
101
|
-
| | |
|
|
102
|
-
| -------- | -------- |
|
|
103
|
-
| Type | `string` |
|
|
104
|
-
| Required | `false` |
|
|
105
|
-
| Default | `'id'` |
|
|
106
|
-
|
|
107
|
-
#### infinite.initialPageParam
|
|
97
|
+
### hooks
|
|
108
98
|
|
|
109
|
-
|
|
99
|
+
Set `true` to generate `useQuery` and `useMutation` hooks on top of the `queryOptions`, `mutationOptions`, and key helpers. [Call operations](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/calling-operations#what-each-plugin-generates) lists every export.
|
|
110
100
|
|
|
111
101
|
| | |
|
|
112
102
|
| -------- | --------- |
|
|
113
|
-
| Type | `
|
|
103
|
+
| Type | `boolean` |
|
|
114
104
|
| Required | `false` |
|
|
115
|
-
| Default | `
|
|
116
|
-
|
|
117
|
-
#### infinite.nextParam
|
|
118
|
-
|
|
119
|
-
Path to the next-page cursor on the response, as dot notation (`'pagination.next.id'`) or array form (`['pagination', 'next', 'id']`).
|
|
120
|
-
|
|
121
|
-
| | |
|
|
122
|
-
| -------- | --------------------------------- |
|
|
123
|
-
| Type | `string \| Array<string> \| null` |
|
|
124
|
-
| Required | `false` |
|
|
125
|
-
| Default | `null` |
|
|
126
|
-
|
|
127
|
-
#### infinite.previousParam
|
|
128
|
-
|
|
129
|
-
Path to the previous-page cursor on the response, in the same dot or array form.
|
|
130
|
-
|
|
131
|
-
| | |
|
|
132
|
-
| -------- | --------------------------------- |
|
|
133
|
-
| Type | `string \| Array<string> \| null` |
|
|
134
|
-
| Required | `false` |
|
|
135
|
-
| Default | `null` |
|
|
136
|
-
|
|
137
|
-
#### infinite.cursorParam
|
|
138
|
-
|
|
139
|
-
Deprecated name of a top-level response field that holds the cursor, read for both `getNextPageParam` and `getPreviousPageParam` when set. Dot paths are not supported. Use `nextParam` and `previousParam` instead.
|
|
140
|
-
|
|
141
|
-
| | |
|
|
142
|
-
| -------- | ---------------- |
|
|
143
|
-
| Type | `string \| null` |
|
|
144
|
-
| Required | `false` |
|
|
145
|
-
| Default | `null` |
|
|
146
|
-
|
|
147
|
-
#### infinite.getNextPageParam
|
|
148
|
-
|
|
149
|
-
Source code for TanStack Query's `getNextPageParam`, copied into the generated code as written. Pass a string or a function. Use it when the next page must be computed instead of read from a field. Takes precedence over `nextParam` and `cursorParam`.
|
|
150
|
-
|
|
151
|
-
| | |
|
|
152
|
-
| -------- | ------------------------------- |
|
|
153
|
-
| Type | `string \| PageParamFn \| null` |
|
|
154
|
-
| Required | `false` |
|
|
155
|
-
| Default | `null` |
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
infinite: {
|
|
159
|
-
queryParam: 'page',
|
|
160
|
-
getNextPageParam: '(lastPage) => (lastPage.hasNext ? lastPage.number + 1 : undefined)',
|
|
161
|
-
getPreviousPageParam: '(firstPage) => (firstPage.number > 0 ? firstPage.number - 1 : undefined)',
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
`definePageParam` types the page and the page parameter, and returns the function's source. A plain function works too. Only the source is copied, so the function cannot reference variables from the config file.
|
|
166
|
-
|
|
167
|
-
```typescript [kubb.config.ts]
|
|
168
|
-
import { definePageParam, pluginReactQuery } from '@kubb/plugin-react-query'
|
|
169
|
-
|
|
170
|
-
type PetsPage = { hasNext: boolean; number: number }
|
|
171
|
-
|
|
172
|
-
pluginReactQuery({
|
|
173
|
-
hooks: true,
|
|
174
|
-
infinite: {
|
|
175
|
-
queryParam: 'page',
|
|
176
|
-
getNextPageParam: definePageParam<PetsPage, number>((lastPage) => (lastPage.hasNext ? lastPage.number + 1 : undefined)),
|
|
177
|
-
},
|
|
178
|
-
})
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
Without `getNextPageParam`, `nextParam` or `cursorParam`, the hook counts pages up from `initialPageParam` until a page is an empty array. Counting works only for array responses, so generation warns for any other response.
|
|
182
|
-
|
|
183
|
-
#### infinite.getPreviousPageParam
|
|
184
|
-
|
|
185
|
-
Source code for TanStack Query's `getPreviousPageParam`, copied into the generated code as written. Takes a string or a function, like `getNextPageParam`. Takes precedence over `previousParam` and `cursorParam`.
|
|
186
|
-
|
|
187
|
-
| | |
|
|
188
|
-
| -------- | ------------------------------- |
|
|
189
|
-
| Type | `string \| PageParamFn \| null` |
|
|
190
|
-
| Required | `false` |
|
|
191
|
-
| Default | `null` |
|
|
192
|
-
|
|
193
|
-
### suspense
|
|
194
|
-
|
|
195
|
-
Adds `useSuspenseQuery` hooks next to the regular query hooks. Pass `{}` to turn it on. Needs TanStack Query v5 or higher and [`hooks: true`](#hooks).
|
|
196
|
-
|
|
197
|
-
| | |
|
|
198
|
-
| -------- | -------------------------- |
|
|
199
|
-
| Type | `Partial<object> \| false` |
|
|
200
|
-
| Required | `false` |
|
|
201
|
-
| Default | `false` |
|
|
105
|
+
| Default | `false` |
|
|
202
106
|
|
|
203
107
|
### query
|
|
204
108
|
|
|
205
|
-
Which operations become queries
|
|
109
|
+
Which operations become queries and where TanStack Query is imported from. `false` skips query output.
|
|
206
110
|
|
|
207
111
|
| | |
|
|
208
112
|
| -------- | -------------------------------------------------------------------- |
|
|
@@ -212,7 +116,7 @@ Which operations become queries, emitting a `queryOptions` factory by default. P
|
|
|
212
116
|
|
|
213
117
|
#### query.methods
|
|
214
118
|
|
|
215
|
-
HTTP methods treated as queries.
|
|
119
|
+
HTTP methods treated as queries. A method in neither list gets no helper, so keep `'QUERY'` when you replace it.
|
|
216
120
|
|
|
217
121
|
| | |
|
|
218
122
|
| -------- | ------------------ |
|
|
@@ -220,11 +124,9 @@ HTTP methods treated as queries.
|
|
|
220
124
|
| Required | `false` |
|
|
221
125
|
| Default | `['GET', 'QUERY']` |
|
|
222
126
|
|
|
223
|
-
Operations whose method is in neither `query.methods` nor `mutation.methods` get no hook. Keep `'QUERY'` here when overriding the list, or QUERY operations are skipped.
|
|
224
|
-
|
|
225
127
|
#### query.importPath
|
|
226
128
|
|
|
227
|
-
Module for
|
|
129
|
+
Module for `queryOptions`, `useQuery`, and their variants, such as a wrapper that sets a default `QueryClient`.
|
|
228
130
|
|
|
229
131
|
| | |
|
|
230
132
|
| -------- | ------------------------- |
|
|
@@ -234,31 +136,28 @@ Module for the `queryOptions` and `useQuery` imports.
|
|
|
234
136
|
|
|
235
137
|
### queryKey
|
|
236
138
|
|
|
237
|
-
Builds
|
|
139
|
+
Builds each query's `queryKey` from the operation `node` and the `variant`: `'query'`, `'suspenseQuery'`, `'infiniteQuery'`, or `'suspenseInfiniteQuery'`. The default key is `[{ url, params }, query, body]`.
|
|
238
140
|
|
|
239
141
|
| | |
|
|
240
142
|
| -------- | ------------------------------------------------------ |
|
|
241
143
|
| Type | `(props: { node, casing, variant }) => Array<unknown>` |
|
|
242
144
|
| Required | `false` |
|
|
243
|
-
| Default |
|
|
244
|
-
|
|
245
|
-
`variant` is `'query'`, `'suspenseQuery'`, `'infiniteQuery'` or `'suspenseInfiniteQuery'`. The default key adds `infinite: true` to infinite variants so they never share a cache entry with the plain query.
|
|
145
|
+
| Default | `queryKeyTransformer` |
|
|
246
146
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
```
|
|
147
|
+
> [!WARNING]
|
|
148
|
+
> Returned strings are copied into the generated code as written, so wrap a string literal in `JSON.stringify(...)`.
|
|
250
149
|
|
|
251
|
-
To extend the default
|
|
150
|
+
To extend the default, spread it. See [TanStack Query keys](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/query-keys).
|
|
252
151
|
|
|
253
152
|
```typescript
|
|
254
153
|
import { queryKeyTransformer } from '@kubb/plugin-react-query'
|
|
255
154
|
|
|
256
|
-
queryKey: (props) => [JSON.stringify(
|
|
155
|
+
queryKey: (props) => [JSON.stringify('v2'), ...queryKeyTransformer(props)]
|
|
257
156
|
```
|
|
258
157
|
|
|
259
158
|
### mutation
|
|
260
159
|
|
|
261
|
-
Which operations become mutations
|
|
160
|
+
Which operations become mutations and where TanStack Query is imported from. `false` skips mutation output.
|
|
262
161
|
|
|
263
162
|
| | |
|
|
264
163
|
| -------- | -------------------------------------------------------------------------------------- |
|
|
@@ -268,7 +167,7 @@ Which operations become mutations, emitting a `mutationOptions` factory by defau
|
|
|
268
167
|
|
|
269
168
|
#### mutation.methods
|
|
270
169
|
|
|
271
|
-
HTTP methods treated as mutations.
|
|
170
|
+
HTTP methods treated as mutations. A method also in `query.methods` stays a query.
|
|
272
171
|
|
|
273
172
|
| | |
|
|
274
173
|
| -------- | ------------------------------------ |
|
|
@@ -278,7 +177,7 @@ HTTP methods treated as mutations.
|
|
|
278
177
|
|
|
279
178
|
#### mutation.importPath
|
|
280
179
|
|
|
281
|
-
Module for
|
|
180
|
+
Module for `mutationOptions` and `useMutation`.
|
|
282
181
|
|
|
283
182
|
| | |
|
|
284
183
|
| -------- | ------------------------- |
|
|
@@ -288,34 +187,155 @@ Module for the `mutationOptions` and `useMutation` imports.
|
|
|
288
187
|
|
|
289
188
|
### mutationKey
|
|
290
189
|
|
|
291
|
-
Builds
|
|
190
|
+
Builds each mutation's `mutationKey`, for batched invalidations or `useMutationState`. It works like [`queryKey`](#querykey) with `variant: 'mutation'`. The default key is `[{ url }]`.
|
|
292
191
|
|
|
293
192
|
| | |
|
|
294
193
|
| -------- | ------------------------------------------------------ |
|
|
295
194
|
| Type | `(props: { node, casing, variant }) => Array<unknown>` |
|
|
296
195
|
| Required | `false` |
|
|
297
|
-
| Default |
|
|
298
|
-
|
|
299
|
-
Extend the default the same way with `mutationKeyTransformer`:
|
|
196
|
+
| Default | `mutationKeyTransformer` |
|
|
300
197
|
|
|
301
198
|
```typescript
|
|
302
199
|
import { mutationKeyTransformer } from '@kubb/plugin-react-query'
|
|
303
200
|
|
|
304
|
-
mutationKey: (props) => [JSON.stringify(
|
|
201
|
+
mutationKey: (props) => [JSON.stringify('v2'), ...mutationKeyTransformer(props)]
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### infinite
|
|
205
|
+
|
|
206
|
+
Adds `infiniteQueryOptions` and `useInfiniteQuery` to each query operation that takes the [`infinite.queryParam`](#infinitequeryparam) parameter. Needs [`hooks: true`](#hooks).
|
|
207
|
+
|
|
208
|
+
| | |
|
|
209
|
+
| -------- | ---------------------------- |
|
|
210
|
+
| Type | `Partial<Infinite> \| false` |
|
|
211
|
+
| Required | `false` |
|
|
212
|
+
| Default | `false` |
|
|
213
|
+
|
|
214
|
+
> [!WARNING]
|
|
215
|
+
> Set `nextParam` or `getNextPageParam`. Otherwise `hasNextPage` never turns false for a non-array response. See [Infinite queries](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/infinite-queries#hasnextpage-never-turns-false).
|
|
216
|
+
|
|
217
|
+
#### infinite.queryParam
|
|
218
|
+
|
|
219
|
+
Query parameter that carries the page cursor.
|
|
220
|
+
|
|
221
|
+
| | |
|
|
222
|
+
| -------- | -------- |
|
|
223
|
+
| Type | `string` |
|
|
224
|
+
| Required | `false` |
|
|
225
|
+
| Default | `'id'` |
|
|
226
|
+
|
|
227
|
+
#### infinite.initialPageParam
|
|
228
|
+
|
|
229
|
+
`pageParam` of the first fetch. Give it the type of the query parameter.
|
|
230
|
+
|
|
231
|
+
| | |
|
|
232
|
+
| -------- | --------- |
|
|
233
|
+
| Type | `unknown` |
|
|
234
|
+
| Required | `false` |
|
|
235
|
+
| Default | `0` |
|
|
236
|
+
|
|
237
|
+
#### infinite.nextParam
|
|
238
|
+
|
|
239
|
+
Path to the next cursor on the response, in dot notation (`'pagination.next.id'`) or array form (`['pagination', 'next', 'id']`).
|
|
240
|
+
|
|
241
|
+
| | |
|
|
242
|
+
| -------- | --------------------------------- |
|
|
243
|
+
| Type | `string \| Array<string> \| null` |
|
|
244
|
+
| Required | `false` |
|
|
245
|
+
| Default | `null` |
|
|
246
|
+
|
|
247
|
+
#### infinite.previousParam
|
|
248
|
+
|
|
249
|
+
Path to the previous cursor, in the same forms as `nextParam`.
|
|
250
|
+
|
|
251
|
+
| | |
|
|
252
|
+
| -------- | --------------------------------- |
|
|
253
|
+
| Type | `string \| Array<string> \| null` |
|
|
254
|
+
| Required | `false` |
|
|
255
|
+
| Default | `null` |
|
|
256
|
+
|
|
257
|
+
#### infinite.getNextPageParam
|
|
258
|
+
|
|
259
|
+
Source of TanStack Query's `getNextPageParam`, for a next page you must compute. Pass a string, a function, or `definePageParam`, which types the page and the page parameter.
|
|
260
|
+
|
|
261
|
+
| | |
|
|
262
|
+
| -------- | ------------------------------- |
|
|
263
|
+
| Type | `string \| PageParamFn \| null` |
|
|
264
|
+
| Required | `false` |
|
|
265
|
+
| Default | `null` |
|
|
266
|
+
|
|
267
|
+
> [!NOTE]
|
|
268
|
+
> Only the function's source is copied, so it cannot use variables from the config file.
|
|
269
|
+
|
|
270
|
+
```typescript [kubb.config.ts]
|
|
271
|
+
import { definePageParam, pluginReactQuery } from '@kubb/plugin-react-query'
|
|
272
|
+
|
|
273
|
+
type PetsPage = { hasNext: boolean; number: number }
|
|
274
|
+
|
|
275
|
+
pluginReactQuery({
|
|
276
|
+
hooks: true,
|
|
277
|
+
infinite: {
|
|
278
|
+
queryParam: 'page',
|
|
279
|
+
getNextPageParam: definePageParam<PetsPage, number>((lastPage) => (lastPage.hasNext ? lastPage.number + 1 : undefined)),
|
|
280
|
+
},
|
|
281
|
+
})
|
|
305
282
|
```
|
|
306
283
|
|
|
284
|
+
#### infinite.getPreviousPageParam
|
|
285
|
+
|
|
286
|
+
Source of TanStack Query's `getPreviousPageParam`, in the same forms as `getNextPageParam`.
|
|
287
|
+
|
|
288
|
+
| | |
|
|
289
|
+
| -------- | ------------------------------- |
|
|
290
|
+
| Type | `string \| PageParamFn \| null` |
|
|
291
|
+
| Required | `false` |
|
|
292
|
+
| Default | `null` |
|
|
293
|
+
|
|
294
|
+
#### infinite.cursorParam
|
|
295
|
+
|
|
296
|
+
Deprecated. Use `nextParam` and `previousParam`. A top-level response field, not a dot path, that holds the cursor for both directions.
|
|
297
|
+
|
|
298
|
+
| | |
|
|
299
|
+
| -------- | ---------------- |
|
|
300
|
+
| Type | `string \| null` |
|
|
301
|
+
| Required | `false` |
|
|
302
|
+
| Default | `null` |
|
|
303
|
+
|
|
304
|
+
### suspense
|
|
305
|
+
|
|
306
|
+
Pass `{}` to add `useSuspenseQuery` hooks, plus `useSuspenseInfiniteQuery` when [`infinite`](#infinite) is set. Needs [`hooks: true`](#hooks).
|
|
307
|
+
|
|
308
|
+
| | |
|
|
309
|
+
| -------- | ----------------- |
|
|
310
|
+
| Type | `object \| false` |
|
|
311
|
+
| Required | `false` |
|
|
312
|
+
| Default | `false` |
|
|
313
|
+
|
|
307
314
|
### customOptions
|
|
308
315
|
|
|
309
|
-
|
|
316
|
+
Calls one function of yours from every hook to share options such as `staleTime`. Kubb also writes a `HookOptions` type, keyed by hook name. Needs [`hooks: true`](#hooks).
|
|
310
317
|
|
|
311
318
|
| | |
|
|
312
319
|
| -------- | --------------------------------------- |
|
|
313
|
-
| Type | `{ importPath: string
|
|
320
|
+
| Type | `{ importPath: string; name?: string }` |
|
|
314
321
|
| Required | `false` |
|
|
315
322
|
|
|
323
|
+
Each hook calls it with `{ hookName, operationId }`, and per-call options win over its result:
|
|
324
|
+
|
|
325
|
+
```typescript [src/gen/hooks/useCustomHookOptions.ts]
|
|
326
|
+
import type { HookOptions } from './HookOptions'
|
|
327
|
+
|
|
328
|
+
export function useCustomHookOptions({ hookName }: { hookName: keyof HookOptions; operationId: string }) {
|
|
329
|
+
if (hookName === 'useGetPetById') {
|
|
330
|
+
return { staleTime: 60_000 } satisfies HookOptions['useGetPetById']
|
|
331
|
+
}
|
|
332
|
+
return {}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
316
336
|
#### customOptions.importPath
|
|
317
337
|
|
|
318
|
-
Module of the
|
|
338
|
+
Module of the function, resolved from the generated hooks folder. If the path is inside the plugin's output folder and the file is missing, Kubb writes a starter file.
|
|
319
339
|
|
|
320
340
|
| | |
|
|
321
341
|
| -------- | ---------------------------------- |
|
|
@@ -324,7 +344,7 @@ Module of the custom-options hook, imported as a named import. The path resolves
|
|
|
324
344
|
|
|
325
345
|
#### customOptions.name
|
|
326
346
|
|
|
327
|
-
Exported name of the
|
|
347
|
+
Exported name of the function.
|
|
328
348
|
|
|
329
349
|
| | |
|
|
330
350
|
| -------- | ------------------------ |
|
|
@@ -332,19 +352,9 @@ Exported name of the custom-options hook.
|
|
|
332
352
|
| Required | `false` |
|
|
333
353
|
| Default | `'useCustomHookOptions'` |
|
|
334
354
|
|
|
335
|
-
### hooks
|
|
336
|
-
|
|
337
|
-
When `false` (the default), only the `queryOptions`, `mutationOptions`, `queryKey` and `mutationKey` helpers are written, using factory imports that work across TanStack Query adapters. Set `true` to also generate `useQuery`, `useSuspenseQuery`, `useInfiniteQuery`, `useSuspenseInfiniteQuery`, and `useMutation`.
|
|
338
|
-
|
|
339
|
-
| | |
|
|
340
|
-
| -------- | --------- |
|
|
341
|
-
| Type | `boolean` |
|
|
342
|
-
| Required | `false` |
|
|
343
|
-
| Default | `false` |
|
|
344
|
-
|
|
345
355
|
### resolver
|
|
346
356
|
|
|
347
|
-
Overrides generated
|
|
357
|
+
Overrides generated names. Members you leave out keep `resolverReactQuery`. See [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver) for the shared members.
|
|
348
358
|
|
|
349
359
|
| | |
|
|
350
360
|
| -------- | ----------------------------------- |
|
|
@@ -357,20 +367,23 @@ Overrides generated file and symbol names. Omitted members keep `resolverReactQu
|
|
|
357
367
|
type ResolverReactQueryPatch = {
|
|
358
368
|
// plus the shared name, file, and imports members
|
|
359
369
|
query?: {
|
|
360
|
-
name?(node: OperationNode): string
|
|
361
|
-
optionsName?(node: OperationNode): string
|
|
362
|
-
keyName?(node: OperationNode): string
|
|
363
|
-
keyTypeName?(node: OperationNode): string
|
|
370
|
+
name?(node: OperationNode): string // 'useGetPetById'
|
|
371
|
+
optionsName?(node: OperationNode): string // 'getPetByIdQueryOptions'
|
|
372
|
+
keyName?(node: OperationNode): string // 'getPetByIdQueryKey'
|
|
373
|
+
keyTypeName?(node: OperationNode): string // 'GetPetByIdQueryKey'
|
|
364
374
|
}
|
|
365
|
-
//
|
|
375
|
+
// same members, with a Suspense, Infinite, or SuspenseInfinite suffix
|
|
376
|
+
suspenseQuery?: ResolverReactQueryPatch['query']
|
|
377
|
+
infiniteQuery?: ResolverReactQueryPatch['query']
|
|
378
|
+
suspenseInfiniteQuery?: ResolverReactQueryPatch['query']
|
|
366
379
|
mutation?: {
|
|
367
|
-
name?(node: OperationNode): string
|
|
368
|
-
optionsName?(node: OperationNode): string
|
|
369
|
-
keyName?(node: OperationNode): string
|
|
380
|
+
name?(node: OperationNode): string // 'useUpdatePet'
|
|
381
|
+
optionsName?(node: OperationNode): string // 'updatePetMutationOptions'
|
|
382
|
+
keyName?(node: OperationNode): string // 'updatePetMutationKey'
|
|
370
383
|
}
|
|
371
384
|
hook?: {
|
|
372
|
-
optionsName?(): string
|
|
373
|
-
customOptionsName?(): string
|
|
385
|
+
optionsName?(): string // 'HookOptions'
|
|
386
|
+
customOptionsName?(): string // 'getCustomHookOptions'
|
|
374
387
|
}
|
|
375
388
|
}
|
|
376
389
|
```
|
package/docs/overview.md
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
# React Query
|
|
2
2
|
|
|
3
|
-
The React Query plugin generates TanStack Query
|
|
3
|
+
The React Query plugin generates TanStack Query `queryOptions` and `mutationOptions` factories with cache keys from your OpenAPI spec, plus optional hooks.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- `hooks: true` adds `useQuery` and `useMutation` hooks, with suspense and infinite variants on request.
|
|
6
|
+
- The plugin ships no HTTP client. Each helper calls a function from your client plugin.
|
|
6
7
|
|
|
7
8
|
## Setup
|
|
8
9
|
|
|
9
|
-
- Add `@kubb/plugin-ts`, or `pluginZod({ inferred: 'codec' })`
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- Add `@kubb/plugin-ts`, or `pluginZod({ inferred: 'codec' })` with `zod` v4 in the app.
|
|
11
|
+
- Add one client plugin: `@kubb/plugin-fetch`, `@kubb/plugin-axios`, or `@kubb/plugin-client`. Leave `sdk` unset on it.
|
|
12
|
+
- Install `@tanstack/react-query` 5.82 or a later v5 release in the app.
|
|
13
|
+
- Set the base URL, auth, and validation on the client plugin. With `@kubb/plugin-client`, your client module owns them.
|
|
12
14
|
|
|
13
15
|
## Options worth knowing
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
| Option | What it does |
|
|
18
|
+
| ------------------- | ------------------------------------------------------------------------------------------------ |
|
|
19
|
+
| `client` | Picks `'fetch'`, `'axios'`, or `'client'` when several client plugins are registered. |
|
|
20
|
+
| `hooks` | Adds the `use*` hooks. `infinite`, `suspense`, and `customOptions` need it. |
|
|
21
|
+
| `query`, `mutation` | Which HTTP methods become queries and mutations. `false` skips them. |
|
|
22
|
+
| `infinite` | Adds infinite queries to operations with the `infinite.queryParam` parameter, `'id'` by default. |
|
|
23
|
+
| `suspense` | `{}` adds `useSuspenseQuery` hooks. |
|
|
24
|
+
| `customOptions` | Routes every hook through your function for shared options. |
|
|
23
25
|
|
|
24
26
|
## Example
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
This config generates hooks that call the Fetch client.
|
|
27
29
|
|
|
28
30
|
```typescript [kubb.config.ts]
|
|
29
31
|
import { defineConfig } from 'kubb/config'
|
|
@@ -43,3 +45,5 @@ export default defineConfig({
|
|
|
43
45
|
],
|
|
44
46
|
})
|
|
45
47
|
```
|
|
48
|
+
|
|
49
|
+
See [Options](https://kubb.dev/extensions/kubb-labs/plugin-react-query/options) for every option. Next, [call operations](https://kubb.dev/extensions/kubb-labs/plugin-react-query/guides/calling-operations).
|
package/kubb-extension.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"name": "plugin-react-query",
|
|
5
5
|
"export": "pluginReactQuery",
|
|
6
6
|
"displayName": "React Query",
|
|
7
|
-
"description": "Generates typed TanStack Query helpers for React from your OpenAPI spec: queryOptions and mutationOptions factories with
|
|
7
|
+
"description": "Generates typed TanStack Query helpers for React from your OpenAPI spec: queryOptions and mutationOptions factories with cache keys, plus optional hooks.",
|
|
8
8
|
"category": "framework",
|
|
9
9
|
"icon": {
|
|
10
10
|
"light": "https://kubb.dev/feature/tanstack.svg"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"optionalDependencies": ["plugin-ts", "plugin-zod"],
|
|
21
21
|
"compatibility": {
|
|
22
|
-
"kubb": ">=5.
|
|
22
|
+
"kubb": ">=5.19.0",
|
|
23
23
|
"node": ">=22.22"
|
|
24
24
|
},
|
|
25
25
|
"role": "consumer",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-react-query",
|
|
3
|
-
"version": "5.10.
|
|
3
|
+
"version": "5.10.4",
|
|
4
4
|
"description": "Generate type-safe TanStack Query (React Query) hooks with Kubb. Covers useQuery, useMutation, useInfiniteQuery, and queryOptions with full TypeScript support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"code-generation",
|
|
@@ -81,16 +81,16 @@
|
|
|
81
81
|
"registry": "https://registry.npmjs.org/"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@kubb/kit": "^5.
|
|
85
|
-
"@kubb/plugin-ts": "^5.5.
|
|
86
|
-
"@kubb/renderer-jsx": "^5.
|
|
84
|
+
"@kubb/kit": "^5.20.1",
|
|
85
|
+
"@kubb/plugin-ts": "^5.5.4",
|
|
86
|
+
"@kubb/renderer-jsx": "^5.20.1"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
89
|
"@internals/client": "0.0.0",
|
|
90
90
|
"@internals/shared": "0.0.0",
|
|
91
91
|
"@internals/tanstack-query": "0.0.0",
|
|
92
92
|
"@internals/utils": "0.0.0",
|
|
93
|
-
"@kubb/plugin-client": "6.0.
|
|
93
|
+
"@kubb/plugin-client": "6.0.4",
|
|
94
94
|
"@tanstack/react-query": "^5.107.1"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|