|
1 | 1 | --- |
2 | 2 | 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. |
4 | 4 | --- |
5 | 5 |
|
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 | +## Route Data Loading |
| 9 | + |
| 10 | +Use the generated `ensureQueryData` functions in your route loaders to prefetch data before the route renders: |
| 11 | + |
| 12 | +```tsx |
| 13 | +// routes/pets.$petId.tsx |
| 14 | +import { createFileRoute } from "@tanstack/react-router"; |
| 15 | +import { ensureUseFindPetByIdData } from "../openapi/queries/ensureQueryData"; |
| 16 | +import { useFindPetById } from "../openapi/queries"; |
| 17 | +import { queryClient } from "../queryClient"; |
| 18 | + |
| 19 | +export const Route = createFileRoute("/pets/$petId")({ |
| 20 | + loader: ({ params }) => |
| 21 | + ensureUseFindPetByIdData(queryClient, { |
| 22 | + path: { petId: Number(params.petId) }, |
| 23 | + }), |
| 24 | + component: PetDetail, |
| 25 | +}); |
| 26 | + |
| 27 | +function PetDetail() { |
| 28 | + const { petId } = Route.useParams(); |
| 29 | + const { data } = useFindPetById({ path: { petId: Number(petId) } }); |
| 30 | + |
| 31 | + return <div>{data?.name}</div>; |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +### For SSR / TanStack Start |
| 36 | + |
| 37 | +When using SSR or TanStack Start, pass `queryClient` from the router context: |
| 38 | + |
| 39 | +```tsx |
| 40 | +export const Route = createFileRoute("/pets/$petId")({ |
| 41 | + loader: ({ context, params }) => |
| 42 | + ensureUseFindPetByIdData(context.queryClient, { |
| 43 | + path: { petId: Number(params.petId) }, |
| 44 | + }), |
| 45 | + component: PetDetail, |
| 46 | +}); |
| 47 | +``` |
| 48 | + |
| 49 | +### Operations Without Path Parameters |
| 50 | + |
| 51 | +```tsx |
| 52 | +import { ensureUseFindPetsData } from "../openapi/queries/ensureQueryData"; |
| 53 | + |
| 54 | +export const Route = createFileRoute("/pets")({ |
| 55 | + loader: () => ensureUseFindPetsData(queryClient), |
| 56 | + component: PetList, |
| 57 | +}); |
| 58 | +``` |
| 59 | + |
| 60 | +## Prefetching on Hover/Touch |
| 61 | + |
| 62 | +Use `prefetchQuery` functions for custom prefetch triggers: |
| 63 | + |
| 64 | +```tsx |
| 65 | +import { prefetchUseFindPetById } from "../openapi/queries/prefetch"; |
| 66 | +import { queryClient } from "../queryClient"; |
| 67 | + |
| 68 | +function PetLink({ petId }: { petId: number }) { |
| 69 | + const handlePrefetch = () => { |
| 70 | + prefetchUseFindPetById(queryClient, { path: { petId } }); |
| 71 | + }; |
| 72 | + |
| 73 | + return ( |
| 74 | + <a |
| 75 | + href={`/pets/${petId}`} |
| 76 | + onMouseEnter={handlePrefetch} |
| 77 | + onTouchStart={handlePrefetch} |
| 78 | + > |
| 79 | + View Pet |
| 80 | + </a> |
| 81 | + ); |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +## Router Configuration |
| 86 | + |
| 87 | +### External Cache Settings |
| 88 | + |
| 89 | +When using TanStack Query as an external cache, configure the router to delegate cache freshness to React Query: |
| 90 | + |
| 91 | +```tsx |
| 92 | +import { createRouter } from "@tanstack/react-router"; |
| 93 | +import { routeTree } from "./routeTree.gen"; |
| 94 | + |
| 95 | +const router = createRouter({ |
| 96 | + routeTree, |
| 97 | + defaultPreloadStaleTime: 0, // Let React Query handle cache freshness |
| 98 | +}); |
| 99 | +``` |
| 100 | + |
| 101 | +### Link Preloading |
| 102 | + |
| 103 | +TanStack Router's `<Link>` component supports intent-based preloading: |
| 104 | + |
| 105 | +```tsx |
| 106 | +<Link to="/pets/$petId" params={{ petId: "1" }} preload="intent"> |
| 107 | + View Pet |
| 108 | +</Link> |
| 109 | +``` |
| 110 | + |
| 111 | +Or set it globally: |
| 112 | + |
| 113 | +```tsx |
| 114 | +const router = createRouter({ |
| 115 | + routeTree, |
| 116 | + defaultPreload: "intent", |
| 117 | + defaultPreloadStaleTime: 0, |
| 118 | +}); |
| 119 | +``` |
| 120 | + |
| 121 | +When using `preload="intent"`, the router automatically calls the route's `loader` on hover/touch. |
| 122 | + |
| 123 | +## Important Notes |
| 124 | + |
| 125 | +### Router Params Are Strings |
| 126 | + |
| 127 | +TanStack Router params are always strings. You must parse them to the correct type: |
| 128 | + |
| 129 | +```tsx |
| 130 | +loader: ({ params }) => |
| 131 | + ensureUseFindPetByIdData(queryClient, { |
| 132 | + path: { petId: Number(params.petId) }, // Convert string to number |
| 133 | + }), |
| 134 | +``` |
| 135 | + |
| 136 | +For type-safe parsing, consider using TanStack Router's `parseParams`: |
| 137 | + |
| 138 | +```tsx |
| 139 | +export const Route = createFileRoute("/pets/$petId")({ |
| 140 | + parseParams: (params) => ({ |
| 141 | + petId: Number(params.petId), |
| 142 | + }), |
| 143 | + loader: ({ params }) => |
| 144 | + ensureUseFindPetByIdData(queryClient, { |
| 145 | + path: { petId: params.petId }, // Already a number |
| 146 | + }), |
| 147 | +}); |
| 148 | +``` |
0 commit comments