React Query Pattern
All server state is managed through React Query. Query and mutation hooks are defined centrally, never inline in components.
Organization
All query/mutation hooks live in frontend/src/lib/queries/ (34 modules). Query key hierarchy is centralized in frontend/src/lib/queryKeys.ts.
| Module | Entity |
|---|---|
buildingQueries.ts | Buildings |
projectQueries.ts | Projects |
contactQueries.ts | Contacts |
quoteQueries.ts | Quotes |
invoiceQueries.ts | Invoices |
hubspot-queries.ts | HubSpot Integration |
workflowQueries.ts | Workflows |
documentObtainingQueries.ts | Document Obtaining |
scenarioQueries.ts | Scenarios |
fundingApplicationQueries.ts | Funding Applications |
Key Factory Pattern
Every module exports a key factory using as const for type-safe cache keys:
export const buildingKeys = {
all: ['buildings'] as const,
lists: () => [...buildingKeys.all, 'list'] as const,
detail: (id: string) => [...buildingKeys.all, id] as const,
};Mutation Hooks
Mutation hooks include cache invalidation, optimistic updates, and toast notifications:
export function useCreateBuilding() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateBuildingInput) => api.buildings.create(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: buildingKeys.all });
toast.success(t('buildings.created'));
},
});
}ESLint Enforcement
An ESLint rule warns when useMutation appears in components/ or pages/ directories. All mutations must be defined in lib/queries/.
Usage in Components
Following Component Decomposition, queries are called in custom hooks (useFooState.ts), not in presentational components:
// useBuildingListState.ts
export function useBuildingListState() {
const buildings = useBuildings(projectId);
const createBuilding = useCreateBuilding();
return { buildings, createBuilding };
}See Also
- State Management — when to use React Query vs alternatives
- API Layer Pattern — the API functions that queries call
- Query Modules — complete module listing
- Frontend Architecture — overall frontend structure
- Component Decomposition — where query hooks live