Skip to content

Commit 664744c

Browse files
committed
feat: add TanStack Router integration with loader factories
1 parent 606ec44 commit 664744c

File tree

11 files changed

+719
-5
lines changed

11 files changed

+719
-5
lines changed

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,73 @@
1010
- Generates custom functions that use React Query's `ensureQueryData` and `prefetchQuery` functions
1111
- Generates query keys and functions for query caching
1212
- Generates pure TypeScript clients generated by [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts)
13+
- Generates loader factories and helpers for [TanStack Router](https://tanstack.com/router) integration
14+
15+
## TanStack Router Integration
16+
17+
The generated `router.ts` file provides loader factories and helpers for seamless integration with TanStack Router.
18+
19+
### Using Loader Factories
20+
21+
Use `loaderUse*` functions in your route definitions to prefetch data:
22+
23+
```tsx
24+
// routes/pets.$petId.tsx
25+
import { createFileRoute } from "@tanstack/react-router";
26+
import { loaderUseFindPetById } from "../openapi/queries/router";
27+
import { queryClient } from "../queryClient";
28+
29+
export const Route = createFileRoute("/pets/$petId")({
30+
loader: ({ params }) =>
31+
loaderUseFindPetById({ queryClient })({
32+
params: { petId: Number(params.petId) },
33+
}),
34+
component: PetDetail,
35+
});
36+
```
37+
38+
For SSR/TanStack Start, pass `queryClient` from the router context:
39+
40+
```tsx
41+
loader: ({ context, params }) =>
42+
loaderUseFindPetById({ queryClient: context.queryClient })({
43+
params: { petId: Number(params.petId) },
44+
}),
45+
```
46+
47+
### Using withQueryPrefetch for Hover/Touch Prefetching
48+
49+
The `withQueryPrefetch` helper enables prefetching on hover or touch:
50+
51+
```tsx
52+
import { withQueryPrefetch } from "../openapi/queries/router";
53+
import { prefetchUseFindPetById } from "../openapi/queries/prefetch";
54+
import { queryClient } from "../queryClient";
55+
56+
function PetLink({ petId }: { petId: number }) {
57+
return (
58+
<a
59+
href={`/pets/${petId}`}
60+
{...withQueryPrefetch(() =>
61+
prefetchUseFindPetById(queryClient, { path: { petId } })
62+
)}
63+
>
64+
View Pet
65+
</a>
66+
);
67+
}
68+
```
69+
70+
### Important Notes
71+
72+
- **Router params are strings**: TanStack Router params are always strings. You must parse them to the correct type (e.g., `Number(params.petId)`) before passing to the loader.
73+
- **External cache configuration**: When using TanStack Query as the cache, set `defaultPreloadStaleTime: 0` in your router configuration to let React Query handle cache freshness:
74+
75+
```tsx
76+
const router = createRouter({
77+
routeTree,
78+
defaultPreloadStaleTime: 0,
79+
});
80+
```
81+
82+
- **Link preloading**: When using `<Link preload="intent">` or `defaultPreload: "intent"`, TanStack Router will automatically call the route's `loader` on hover/touch. If your loader uses `ensureUse*Data`, prefetching happens automatically without needing `withQueryPrefetch`.
Lines changed: 170 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,174 @@
11
---
22
title: TanStack Router Example
3-
description: A simple example of using TanStack Router with OpenAPI React Query Codegen.
3+
description: Using TanStack Router with OpenAPI React Query Codegen for data loading and prefetching.
44
---
55

6-
Example of using Next.js can be found in the [`examples/tanstack-router-app`](https://github.com/7nohe/openapi-react-query-codegen/tree/main/examples/tanstack-router-app) directory of the repository.
6+
Example of using TanStack Router can be found in the [`examples/tanstack-router-app`](https://github.com/7nohe/openapi-react-query-codegen/tree/main/examples/tanstack-router-app) directory of the repository.
7+
8+
## Generated Files
9+
10+
The codegen generates a `router.ts` file that provides:
11+
12+
- **Loader factories** (`loaderUse*`) for route data loading
13+
- **`withQueryPrefetch`** helper for hover/touch prefetching
14+
15+
## Using Loader Factories
16+
17+
Use `loaderUse*` functions in your route definitions to prefetch data before the route renders:
18+
19+
```tsx
20+
// routes/pets.$petId.tsx
21+
import { createFileRoute } from "@tanstack/react-router";
22+
import { loaderUseFindPetById } from "../openapi/queries/router";
23+
import { queryClient } from "../queryClient";
24+
25+
export const Route = createFileRoute("/pets/$petId")({
26+
loader: ({ params }) =>
27+
loaderUseFindPetById({ queryClient })({
28+
params: { petId: Number(params.petId) },
29+
}),
30+
component: PetDetail,
31+
});
32+
33+
function PetDetail() {
34+
const { petId } = Route.useParams();
35+
const { data } = useFindPetById({ path: { petId: Number(petId) } });
36+
37+
return <div>{data?.name}</div>;
38+
}
39+
```
40+
41+
### For SSR / TanStack Start
42+
43+
When using SSR or TanStack Start, pass `queryClient` from the router context instead of importing it directly:
44+
45+
```tsx
46+
export const Route = createFileRoute("/pets/$petId")({
47+
loader: ({ context, params }) =>
48+
loaderUseFindPetById({ queryClient: context.queryClient })({
49+
params: { petId: Number(params.petId) },
50+
}),
51+
component: PetDetail,
52+
});
53+
```
54+
55+
### Operations Without Path Parameters
56+
57+
For operations without path parameters, the loader is simpler:
58+
59+
```tsx
60+
import { loaderUseFindPets } from "../openapi/queries/router";
61+
62+
export const Route = createFileRoute("/pets")({
63+
loader: () => loaderUseFindPets({ queryClient })(),
64+
component: PetList,
65+
});
66+
```
67+
68+
### Passing Additional Options
69+
70+
You can pass additional client options through the `clientOptions` parameter:
71+
72+
```tsx
73+
loader: ({ params }) =>
74+
loaderUseFindPetById({
75+
queryClient,
76+
clientOptions: {
77+
headers: { "X-Custom-Header": "value" },
78+
},
79+
})({
80+
params: { petId: Number(params.petId) },
81+
}),
82+
```
83+
84+
## Using withQueryPrefetch
85+
86+
The `withQueryPrefetch` helper enables prefetching on hover or touch events. This is useful for custom prefetch triggers outside of TanStack Router's built-in `<Link>` preloading:
87+
88+
```tsx
89+
import { withQueryPrefetch } from "../openapi/queries/router";
90+
import { prefetchUseFindPetById } from "../openapi/queries/prefetch";
91+
import { queryClient } from "../queryClient";
92+
93+
function PetLink({ petId }: { petId: number }) {
94+
return (
95+
<a
96+
href={`/pets/${petId}`}
97+
{...withQueryPrefetch(() =>
98+
prefetchUseFindPetById(queryClient, { path: { petId } })
99+
)}
100+
>
101+
View Pet
102+
</a>
103+
);
104+
}
105+
```
106+
107+
This spreads `onMouseEnter` and `onTouchStart` handlers that trigger the prefetch.
108+
109+
## Router Configuration
110+
111+
### External Cache Settings
112+
113+
When using TanStack Query as an external cache, configure the router to delegate cache freshness to React Query:
114+
115+
```tsx
116+
import { createRouter } from "@tanstack/react-router";
117+
import { routeTree } from "./routeTree.gen";
118+
119+
const router = createRouter({
120+
routeTree,
121+
defaultPreloadStaleTime: 0, // Let React Query handle cache freshness
122+
});
123+
```
124+
125+
### Link Preloading
126+
127+
TanStack Router's `<Link>` component supports intent-based preloading:
128+
129+
```tsx
130+
<Link to="/pets/$petId" params={{ petId: "1" }} preload="intent">
131+
View Pet
132+
</Link>
133+
```
134+
135+
Or set it globally:
136+
137+
```tsx
138+
const router = createRouter({
139+
routeTree,
140+
defaultPreload: "intent",
141+
defaultPreloadStaleTime: 0,
142+
});
143+
```
144+
145+
When using `preload="intent"`, the router automatically calls the route's `loader` on hover/touch. If your loader uses `ensureUse*Data` (which the generated loaders do), prefetching happens automatically.
146+
147+
## Important Notes
148+
149+
### Router Params Are Strings
150+
151+
TanStack Router params are always strings. You must parse them to the correct type before passing to the loader:
152+
153+
```tsx
154+
// Router params: { petId: string }
155+
// API expects: { petId: number }
156+
loader: ({ params }) =>
157+
loaderUseFindPetById({ queryClient })({
158+
params: { petId: Number(params.petId) }, // Convert string to number
159+
}),
160+
```
161+
162+
For type-safe parsing, consider using TanStack Router's `parseParams`:
163+
164+
```tsx
165+
export const Route = createFileRoute("/pets/$petId")({
166+
parseParams: (params) => ({
167+
petId: Number(params.petId),
168+
}),
169+
loader: ({ params }) =>
170+
loaderUseFindPetById({ queryClient })({
171+
params: { petId: params.petId }, // Already a number
172+
}),
173+
});
174+
```

docs/src/content/docs/guides/introduction.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ OpenAPI React Query Codegen is a code generator for creating React Query (also k
1212
- Generates custom functions that use React Query's `ensureQueryData` and `prefetchQuery` functions
1313
- Generates query keys and functions for query caching
1414
- Generates pure TypeScript clients generated by [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts)
15+
- Generates loader factories and helpers for [TanStack Router](https://tanstack.com/router) integration
1516

1617

1718
## Installation
@@ -75,6 +76,7 @@ openapi/
7576
│ ├── infiniteQueries.ts
7677
│ ├── prefetch.ts
7778
│ ├── queries.ts
79+
│ ├── router.ts
7880
│ └── suspense.ts
7981
└── requests
8082
├── index.ts
@@ -177,8 +179,9 @@ export default App;
177179
- ensureQueryData.ts Generated ensureQueryData functions
178180
- queries.ts Generated query/mutation hooks
179181
- infiniteQueries.ts Generated infinite query hooks
180-
- suspenses.ts Generated suspense hooks
182+
- suspense.ts Generated suspense hooks
181183
- prefetch.ts Generated prefetch functions
184+
- router.ts Generated loader factories and helpers for TanStack Router
182185
- requests Output code generated by `@hey-api/openapi-ts`
183186

184187
</FileTree>

docs/src/content/docs/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Card, CardGrid } from '@astrojs/starlight/components';
2424
Generates custom react hooks that use React(TanStack) Query's useQuery, useSuspenseQuery, useMutation and useInfiniteQuery hooks.
2525
</Card>
2626
<Card title="Prefetching & Router Integration" icon="vercel">
27-
Generates custom functions that use React Query's `ensureQueryData` and `prefetchQuery` functions to integrate into frameworks like Next.js and Remix.
27+
Generates custom functions that use React Query's `ensureQueryData` and `prefetchQuery` functions, plus loader factories for TanStack Router, to integrate into frameworks like Next.js, Remix, and TanStack Start.
2828
</Card>
2929
<Card title="Pure TypeScript Clients" icon="seti:typescript">
3030
Generates pure TypeScript clients generated by [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts) in case you still want to do type-safe API calls without React Query.

src/constants.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export const OpenApiRqFiles = {
1313
index: "index",
1414
prefetch: "prefetch",
1515
ensureQueryData: "ensureQueryData",
16+
router: "router",
1617
} as const;

0 commit comments

Comments
 (0)