TanStack Query (React Query): Handling HTTP Requests with EaseEntry 9 of 10
Organizing Queries and Services
Conventions that keep query keys, fetch functions, and components maintainable as the app grows.
Notes
| Concern | Recommendation |
|---|---|
| HTTP | Plain fetch functions in services/, throwing on error |
| Query client | One instance in util/query-client.ts |
| Query keys | Consistent hierarchy: ['events'], ['events', { search }], ['events', id] |
| Reuse | Wrap repeated useQuery calls in custom hooks (useEvent(id)) |
| Defaults | Set app-wide staleTime in QueryClient |
| Writes | Always useMutation, never useQuery |
| After writes | Invalidate by prefix (['events']) |
| Debugging | React Query Devtools |
Code compare
// hooks/useEvent.ts — reusable query hookexport function useEvent(id: string) { return useQuery({ queryKey: ["events", id], queryFn: ({ signal }) => fetchEvent({ id, signal }), staleTime: 60 * 1000, });}src/├── util/│ └── query-client.ts├── services/│ └── events.ts // fetchEvents, fetchEvent, createNewEvent, updateEvent, deleteEvent├── hooks/│ └── useEvent.ts├── components/│ ├── NewEventsSection.tsx│ └── FindEventSection.tsx└── pages/ ├── NewEvent.tsx // useMutation + invalidate ├── EventDetails.tsx // useQuery + delete mutation └── EditEvent.tsx // optimistic updatesrc/app/├── services/│ ├── events.service.ts // HttpClient calls + version signal│ └── events-cache.service.ts // optional staleTime cache├── events/│ ├── new-events-section.component.ts // rxResource│ ├── find-event-section.component.ts // rxResource with params│ ├── event-details.component.ts // rxResource + optimistic update│ └── new-event.component.ts // service call + invalidate└── app.config.ts // provideHttpClient()