mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-03 11:37:36 +00:00
- 16 cross-shell utilities converted to sh/bash chezmoi executables: ai c2p cp-appid extract_agents fab gdc gh-sonr-org-migrate ghg-clone ghn gho git-summary launch_omp_livediff_overlay lc-elir mdcp mdp pj (ghg-clone not named ghg: unrelated cargo binary owns that name) - cwd/history helpers stay per-shell: yy c cd clip-last + ghg/ghn/gho cd-wrappers in bash/functions/ and zsh/functions/, loaded by rc files - fish keeps only shell-state functions; converted ones now hit PATH - cp-appid ignore gating moved to .local/bin path - dot_agents/skills: 82 skills materialized from dotstate storage so dot_claude skill symlinks resolve on fresh bootstrap; dotstate profile/symlinks.json released .agents/skills .bashrc .zshrc
4.3 KiB
4.3 KiB
setup-query-client-context: Pass QueryClient Through Router Context
Priority: CRITICAL
Explanation
Pass the QueryClient instance through TanStack Router's context system rather than using a global. This enables proper SSR with per-request clients, testability, and type-safe access in loaders. Use @tanstack/react-router-ssr-query for automatic SSR integration.
Bad Example
// lib/query-client.ts - Global singleton
export const queryClient = new QueryClient()
// routes/posts.tsx - Importing global
import { queryClient } from '@/lib/query-client'
export const Route = createFileRoute('/posts')({
loader: async () => {
// Using global - breaks SSR, harder to test
return queryClient.fetchQuery(postQueries.list())
},
})
Good Example: Modern Router Setup
// routes/__root.tsx
import { createRootRouteWithContext } from '@tanstack/react-router'
import { QueryClient } from '@tanstack/react-query'
interface RouterContext {
queryClient: QueryClient
}
export const Route = createRootRouteWithContext<RouterContext>()({
component: RootComponent,
})
// router.tsx
import { QueryClient } from '@tanstack/react-query'
import { createRouter } from '@tanstack/react-router'
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
import { routeTree } from './routeTree.gen'
export function getRouter() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
staleTime: 1000 * 60 * 2, // 2 minutes
},
},
})
const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: 'intent',
defaultPreloadStaleTime: 0,
scrollRestoration: true,
})
setupRouterSsrQueryIntegration({
router,
queryClient,
})
return router
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof getRouter>
}
}
// routes/posts.tsx - Access from context
export const Route = createFileRoute('/posts')({
loader: async ({ context: { queryClient } }) => {
// Type-safe access to queryClient from context
await queryClient.ensureQueryData(postQueries.list())
},
})
Good Example: Root Route with Context
// routes/__root.tsx
import { createRootRouteWithContext, Outlet, HeadContent, Scripts } from '@tanstack/react-router'
import { QueryClient } from '@tanstack/react-query'
interface RouterContext {
queryClient: QueryClient
user: User | null
}
export const Route = createRootRouteWithContext<RouterContext>()({
component: RootComponent,
beforeLoad: async ({ context }) => {
// Prefetch auth or other global data
await context.queryClient.ensureQueryData(authQueryOptions)
},
})
function RootComponent() {
return (
<html>
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
)
}
TanStack Start handles SSR and hydration automatically via the Vite plugin. No separate entry files needed.
Good Example: Testing with Mock QueryClient
// tests/posts.test.tsx
import { createRouter, RouterProvider } from '@tanstack/react-router'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render } from '@testing-library/react'
function renderWithProviders(route: string) {
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
},
})
const router = createRouter({
routeTree,
context: { queryClient },
Wrap: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
})
return {
...render(<RouterProvider router={router} />),
queryClient,
}
}
test('loads posts', async () => {
const { queryClient } = renderWithProviders('/posts')
// Pre-populate cache for testing
queryClient.setQueryData(['posts'], mockPosts)
// ... assertions
})
Context
- Router context flows to all loaders and beforeLoad hooks
- Creating QueryClient per request is essential for SSR
- Use
setupRouterSsrQueryIntegrationfor automatic SSR handling - Access queryClient via
contextparameter in loaders - This pattern enables clean dependency injection for testing
- Install:
npm install @tanstack/react-router-ssr-query