You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* added global error handling for queries as well
* cerated new model types for strikes
* added a key factory for strikes
* added a mappers for domain types
* added a doc that explains the structure
|`VITE_BACKEND_PROXY_TARGET`| Backend API URL |`http://localhost:7777`| No|
70
+
|`VITE_GOOGLE_CLIENT_ID`| Google OAuth Client ID | - | Yes|
69
71
70
72
### API Proxy Configuration
73
+
71
74
You need to set up `VITE_BACKEND_PROXY_TARGET` variable to point to the correct backend URL. If you use the default http://localhost:7777, you need to run the local server first. Read more about local backend development in the server's [README.md](../server/)
72
75
The development server automatically proxies API requests:
76
+
73
77
-`/api/*` → Backend server
74
78
-`/api-docs/*` → Backend API documentation
75
79
76
80
This eliminates CORS issues during development.
77
81
78
82
## 🗂️ Client Structure
83
+
79
84
-`src/`: Contains all React components and application logic.
80
85
-`assets/`: Contains all the assets and images used.
81
86
-`components/`: Reusable UI components.
@@ -98,7 +103,171 @@ Make sure you have `VITE_GOOGLE_CLIENT_ID` set up correctly. Check out the serve
98
103
## API Integration
99
104
100
105
The client communicates with the backend API through:
106
+
101
107
-**Axios** for HTTP requests
102
108
-**React Query** for caching and state management
103
109
-**Automatic retry** for failed requests
104
110
-**Optimistic updates** for better UX
111
+
112
+
---
113
+
114
+
## Using TanStack: Example with Strikes Feature (wip)
115
+
116
+
This project uses React Query's `useQuery` and `useMutation` hooks for data fetching and updates. Here’s how to organize your files and use these hooks, using the `strikes` feature as an example:
117
+
118
+
### File Structure for API and Data Layers
119
+
120
+
```
121
+
strikes/
122
+
├── api/
123
+
│ ├── api.ts # API calls (fetch, add, edit, delete)
124
+
│ ├── mapper.ts # Maps API types to domain models
125
+
│ ├── types.ts # API request/response types
126
+
├── data/
127
+
│ ├── keys.ts # Query key factory for React Query
128
+
│ ├── mutations.ts # React Query mutation hooks
129
+
│ ├── strike-queries.ts # React Query query hooks
130
+
```
131
+
132
+
-`api.ts`: clean calls using axios
133
+
-`mapper.ts`: Sometimes we get from the backend more information than we are using in our UI, or the information is arranged differently. Because of this, it's good to separate the business logic that transforms API responses into the shape your UI needs.
134
+
This file contains functions that map API types (often matching backend structure) to domain models (used in your frontend), ensuring consistency and making it easier to adapt if the backend changes or if you want to refactor your UI.
135
+
For example, you might convert snake_case fields to camelCase, filter out unused properties, or maybe flatten nested data/
136
+
-`types.ts`: specifies the request and response type. This way it's very clear to see what data is sent to the backend and what we expect to get back.
137
+
138
+
-`keys.ts`: In this file we define the key factory for the queries used in the feature. Query keys are unique identifiers for each query in React Query. They help React Query know which data to cache, refetch, or update.
139
+
A key factory is a function or object that generates consistent, structured keys for your queries. This makes it easy to manage cache and invalidation, especially as your feature grows.
140
+
141
+
-`mutations.ts`: This file contains React Query mutation hooks for creating, updating, or deleting data. Mutations trigger changes on the server and, on success, typically invalidate relevant queries to keep the UI in sync.
142
+
-`queries.ts`: This file contains React Query query hooks for fetching data from the server. Queries use structured keys to manage caching, loading states, and automatic refetching, making data fetching reliable and efficient.
💡 **Note:** This function creates two query keys for us.
170
+
171
+
1. all: the key looks like this: ['strikes']
172
+
2. list: the key looks like this: ['strikes', 'list', `traineeId`].
173
+
And when invalidating the cache, if you use `queryKey: strikeKeys.list(traineeId)`, it invalidates the cache for this specific traineeId. But if you call `queryKey: strikeKeys.all()`, it will invalidate all the cache queries that start with 'strikes'. Which is pretty cool :)
It’s important to invalidate the relevant query after a mutation completes. While the mutation is still pending, React Query will keep the loading state active until the operation finishes and the cache is refreshed.
0 commit comments