Skip to content

feat(console): introduce TanStack Query for client data fetching#284

Closed
jeroenrinzema wants to merge 1 commit into
mainfrom
feat/tanstack-query
Closed

feat(console): introduce TanStack Query for client data fetching#284
jeroenrinzema wants to merge 1 commit into
mainfrom
feat/tanstack-query

Conversation

@jeroenrinzema

Copy link
Copy Markdown
Contributor

Why

The console's client-side data fetching is currently split across two patterns: React Router loaders for route-level data, and a homegrown useResolver hook for in-component fetching. useResolver has no caching, no request dedup, no background revalidation, and no mutation→invalidation wiring — every list view re-implements pagination by hand and refreshes after writes with an imperative reload().

This PR introduces TanStack Query as the console's caching data layer and migrates the Users list view as the reference pattern. The remaining ~17 list views keep working unchanged and can adopt the same approach incrementally.

This is the first slice of the TanStack assessment — Query is the highest-leverage piece. Router (we're on React Router 7) and Form (react-hook-form) are intentionally left as-is.

What's in here

Infrastructure

  • lib/query-client.ts — shared QueryClient with dashboard-tuned defaults (30s staleTime, single retry, focus revalidation).
  • lib/query-keys.ts — centralised, hierarchical query-key factory so a mutation can invalidate lists and detail views by prefix.
  • App.tsx — mounts QueryClientProvider; React Query Devtools enabled in dev only.

Users view migration

  • Swaps useResolver for useQuery with keepPreviousData, so paging and typing in search no longer flash an empty table.
  • Converts user creation and bulk import to useMutation, refreshing the list via cache invalidation instead of reload().
  • isCreating is now derived from mutation.isPending — one less piece of manual state.

Notes / follow-ups

  • Loaders are deliberately untouched; the clean end-state is Query as the single content layer with loaders reduced to thin auth/redirect guards.
  • Suggested next steps: adopt the same pattern in the other useResolver-based list views, and consider a shared useSearchQuery helper to remove the per-view pagination boilerplate.

Verification

  • tsc --noEmit clean
  • eslint clean on changed files
  • pnpm build succeeds (only pre-existing chunk-size / dynamic-import warnings)

Adds @tanstack/react-query as the console's caching data layer and
migrates the Users list view as the reference pattern.

Infrastructure:
- Shared QueryClient (lib/query-client.ts) with dashboard-tuned defaults
  (30s staleTime, single retry, focus revalidation).
- Centralised query-key factory (lib/query-keys.ts) so mutations can
  invalidate lists and detail views by hierarchical prefix.
- QueryClientProvider mounted in App; Devtools wired up in dev only.

Users view migration:
- Replaces the homegrown useResolver (no cache, no dedup, manual reload)
  with useQuery + keepPreviousData for flicker-free pagination/search.
- Converts create + bulk-import to useMutation, refreshing the list via
  cache invalidation instead of an imperative reload() call.

Remaining list views keep working unchanged; they can adopt the same
pattern incrementally.
@jeroenrinzema jeroenrinzema deleted the feat/tanstack-query branch June 30, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant