Capítulo 24 de 24
This example extends the router/app monorepo split one step further: a dedicated post-query package owns TanStack Query's queryOptions() definitions, and the router package consumes them by holding a QueryClient in router context, letting route loaders (in yet another package or the router package itself) call queryClient.ensureQueryData(postQueryOptions(id)) without the router package needing to know how posts are fetched.
router package (routeTree.gen.ts), same overall shape as ch022/ch023@tanstack/react-router, @tanstack/router-plugin, @tanstack/react-query, @tanstack/history, redaxios, zod, plus @router-mono-react-query/post-query as a workspace:* dependency of the router packagepackages/router/src/router.tsx creates a QueryClient and passes it via router context. packages/post-query/src/postQueryOptions.tsx defines postQueryOptions(postId) using queryOptions() and a fetchPost helper, isolated in its own package so it can be reused or swapped independently of the router's routing logic.// packages/router/src/router.tsx
export const queryClient = new QueryClient()
export const router = createRouter({
routeTree,
context: { queryClient },
defaultPendingComponent: () => (
<div>Loading form global pending component...</div>
),
// This makes the loader only wait 200ms before showing the pending component
defaultPendingMs: 200,
defaultPreload: 'intent',
// Since we're using React Query, loader calls should never be considered stale
defaultPreloadStaleTime: 0,
scrollRestoration: true,
})
// packages/post-query/src/postQueryOptions.tsx
export const postQueryOptions = (postId: string) =>
queryOptions({
queryKey: ['posts', { postId }],
queryFn: () => fetchPost(postId),
})
post-query), separate from both the router package (route tree/loaders) and the app package (components), so query definitions can be versioned, tested, and reused independently of routing concerns.defaultPendingMs: 200 shortens how long the router waits before showing defaultPendingComponent, useful once loaders are doing real network work via React Query.post-query) mirrors the same rationale as splitting routes from components in ch022: each concern gets its own package boundary and can be swapped or versioned independently.defaultPreloadStaleTime: 0 is set here too, this is a recurring pairing whenever a router's context.queryClient is the source of truth for freshness rather than the router's own preload cache.QueryClient still lives in the router package (not a fourth package), it's the router's context wiring, closest in responsibility to createRouter itself.router/app package shape.ensureQueryData/queryOptions() pattern used here across a package boundary.