query-harbor 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +349 -349
- package/dist/hooks/apiHandler.d.ts +24 -0
- package/dist/hooks/useCookie.d.ts +24 -0
- package/dist/hooks/useGlobalInfiniteQuery.d.ts +28 -0
- package/dist/hooks/useGlobalMutation.d.ts +32 -0
- package/dist/hooks/useGlobalQuery.d.ts +58 -0
- package/dist/index.d.ts +4 -0
- package/dist/query-harbor.es.js +165 -211
- package/dist/query-harbor.umd.js +1 -1
- package/package.json +61 -47
package/README.md
CHANGED
|
@@ -1,350 +1,350 @@
|
|
|
1
|
-
# Query Harbor
|
|
2
|
-
|
|
3
|
-
A collection of custom React hooks built on top of TanStack Query (formerly React Query) for handling API requests, mutations, and cookie management. These hooks provide a standardized way to handle data fetching, caching, and state management in React applications.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Installation](#installation)
|
|
8
|
-
- [Hooks Overview](#hooks-overview)
|
|
9
|
-
- [useGlobalQuery](#useglobalquery)
|
|
10
|
-
- [useGlobalMutation](#useglobalmutation)
|
|
11
|
-
- [useGlobalInfiniteQuery](#useglobalinfinitequery)
|
|
12
|
-
- [useCookie](#usecookie)
|
|
13
|
-
- [Usage Examples](#usage-examples)
|
|
14
|
-
- [API Reference](#api-reference)
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
# Install required dependencies
|
|
20
|
-
npm install @tanstack/react-query react-cookie axios
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Hooks Overview
|
|
24
|
-
|
|
25
|
-
### useGlobalQuery
|
|
26
|
-
|
|
27
|
-
A custom hook for making standard API requests with built-in caching and state management.
|
|
28
|
-
|
|
29
|
-
#### Features
|
|
30
|
-
- Automatic authentication header handling
|
|
31
|
-
- Configurable cache and stale times
|
|
32
|
-
- Built-in error handling
|
|
33
|
-
- Query invalidation support
|
|
34
|
-
|
|
35
|
-
#### Basic Usage
|
|
36
|
-
|
|
37
|
-
```javascript
|
|
38
|
-
const {
|
|
39
|
-
queryData,
|
|
40
|
-
isLoading,
|
|
41
|
-
isError,
|
|
42
|
-
error,
|
|
43
|
-
refetchQuery
|
|
44
|
-
} = useGlobalQuery({
|
|
45
|
-
url: '/api/users',
|
|
46
|
-
queryKey: ['users'],
|
|
47
|
-
methodType: 'GET'
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### useGlobalMutation
|
|
52
|
-
|
|
53
|
-
A custom hook for handling data mutations (create, update, delete operations) with support for FormData.
|
|
54
|
-
|
|
55
|
-
#### Features
|
|
56
|
-
- FormData support with nested object handling
|
|
57
|
-
- Automatic query invalidation after successful mutation
|
|
58
|
-
- Priority data support
|
|
59
|
-
- Built-in error handling
|
|
60
|
-
|
|
61
|
-
#### Basic Usage
|
|
62
|
-
|
|
63
|
-
```javascript
|
|
64
|
-
const {
|
|
65
|
-
runMutation,
|
|
66
|
-
mutationLoading,
|
|
67
|
-
mutationData,
|
|
68
|
-
mutationError,
|
|
69
|
-
isMutationSucceeded
|
|
70
|
-
} = useGlobalMutation({
|
|
71
|
-
url: '/api/users',
|
|
72
|
-
queriesToInvalidate: ['users'],
|
|
73
|
-
methodType: 'POST',
|
|
74
|
-
data: userData
|
|
75
|
-
});
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
#### FormData Upload Examples
|
|
79
|
-
|
|
80
|
-
##### Basic FormData Upload
|
|
81
|
-
|
|
82
|
-
```javascript
|
|
83
|
-
const {
|
|
84
|
-
runMutation,
|
|
85
|
-
mutationLoading
|
|
86
|
-
} = useGlobalMutation({
|
|
87
|
-
url: '/api/upload',
|
|
88
|
-
queriesToInvalidate: ['files'],
|
|
89
|
-
methodType: 'POST',
|
|
90
|
-
isFormData: true,
|
|
91
|
-
data: {
|
|
92
|
-
file: fileObject,
|
|
93
|
-
title: 'My Document'
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
##### Complex FormData with Arrays
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
// Without excludedIndexKeys
|
|
102
|
-
const data = {
|
|
103
|
-
files: [file1, file2],
|
|
104
|
-
metadata: {
|
|
105
|
-
titles: ['Doc 1', 'Doc 2']
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// This will generate FormData with structure:
|
|
110
|
-
// files[0] = file1
|
|
111
|
-
// files[1] = file2
|
|
112
|
-
// metadata[titles][0] = Doc 1
|
|
113
|
-
// metadata[titles][1] = Doc 2
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
##### Using excludedIndexKeys
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
const MultipleFileUpload = () => {
|
|
120
|
-
const {
|
|
121
|
-
runMutation,
|
|
122
|
-
mutationLoading
|
|
123
|
-
} = useGlobalMutation({
|
|
124
|
-
url: '/api/upload-multiple',
|
|
125
|
-
queriesToInvalidate: ['files'],
|
|
126
|
-
methodType: 'POST',
|
|
127
|
-
isFormData: true,
|
|
128
|
-
// Specify which keys should not include array indices
|
|
129
|
-
excludedIndexKeys: ['files', 'documents'],
|
|
130
|
-
data: {
|
|
131
|
-
files: [file1, file2, file3],
|
|
132
|
-
documents: [docFile1, docFile2],
|
|
133
|
-
metadata: {
|
|
134
|
-
titles: ['Doc 1', 'Doc 2', 'Doc 3'],
|
|
135
|
-
categories: ['Cat 1', 'Cat 2', 'Cat 3']
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<button onClick={() => runMutation()}>
|
|
142
|
-
Upload Files
|
|
143
|
-
</button>
|
|
144
|
-
);
|
|
145
|
-
};
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
The above example will generate FormData with the following structure:
|
|
149
|
-
```plaintext
|
|
150
|
-
// Keys with excludedIndexKeys:
|
|
151
|
-
files = file1
|
|
152
|
-
files = file2
|
|
153
|
-
files = file3
|
|
154
|
-
documents = docFile1
|
|
155
|
-
documents = docFile2
|
|
156
|
-
|
|
157
|
-
// Regular array keys (maintain indices):
|
|
158
|
-
metadata[titles][0] = Doc 1
|
|
159
|
-
metadata[titles][1] = Doc 2
|
|
160
|
-
metadata[titles][2] = Doc 3
|
|
161
|
-
metadata[categories][0] = Cat 1
|
|
162
|
-
metadata[categories][1] = Cat 2
|
|
163
|
-
metadata[categories][2] = Cat 3
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
##### Real-World Example: Multiple File Upload with Metadata
|
|
167
|
-
|
|
168
|
-
```javascript
|
|
169
|
-
const DocumentUploadForm = () => {
|
|
170
|
-
const [files, setFiles] = useState([]);
|
|
171
|
-
const [metadata, setMetadata] = useState({
|
|
172
|
-
department: 'HR',
|
|
173
|
-
tags: ['confidential', 'employee'],
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
const {
|
|
177
|
-
runMutation,
|
|
178
|
-
mutationLoading,
|
|
179
|
-
isMutationSucceeded
|
|
180
|
-
} = useGlobalMutation({
|
|
181
|
-
url: '/api/documents/upload',
|
|
182
|
-
queriesToInvalidate: ['documents'],
|
|
183
|
-
methodType: 'POST',
|
|
184
|
-
isFormData: true,
|
|
185
|
-
excludedIndexKeys: ['files'], // files will be sent without indices
|
|
186
|
-
data: {
|
|
187
|
-
files: files,
|
|
188
|
-
metadata: metadata,
|
|
189
|
-
timestamp: new Date().toISOString(),
|
|
190
|
-
user: {
|
|
191
|
-
id: currentUserId,
|
|
192
|
-
role: userRole
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const handleFileChange = (e) => {
|
|
198
|
-
setFiles(Array.from(e.target.files));
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const handleUpload = () => {
|
|
202
|
-
runMutation();
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
return (
|
|
206
|
-
<div>
|
|
207
|
-
<input
|
|
208
|
-
type="file"
|
|
209
|
-
multiple
|
|
210
|
-
onChange={handleFileChange}
|
|
211
|
-
/>
|
|
212
|
-
{mutationLoading ? (
|
|
213
|
-
<p>Uploading...</p>
|
|
214
|
-
) : (
|
|
215
|
-
<button onClick={handleUpload}>
|
|
216
|
-
Upload Documents
|
|
217
|
-
</button>
|
|
218
|
-
)}
|
|
219
|
-
{isMutationSucceeded && (
|
|
220
|
-
<p>Upload completed successfully!</p>
|
|
221
|
-
)}
|
|
222
|
-
</div>
|
|
223
|
-
);
|
|
224
|
-
};
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
This will generate FormData where:
|
|
228
|
-
- Multiple files are sent with the same key name ('files')
|
|
229
|
-
- Metadata is properly nested with array indices preserved
|
|
230
|
-
- Additional data is structured appropriately
|
|
231
|
-
|
|
232
|
-
The resulting FormData structure will be:
|
|
233
|
-
```plaintext
|
|
234
|
-
files = File1
|
|
235
|
-
files = File2
|
|
236
|
-
metadata[department] = HR
|
|
237
|
-
metadata[tags][0] = confidential
|
|
238
|
-
metadata[tags][1] = employee
|
|
239
|
-
timestamp = 2024-02-23T10:00:00.000Z
|
|
240
|
-
user[id] = 123
|
|
241
|
-
user[role] = admin
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
#### When to Use excludedIndexKeys
|
|
245
|
-
|
|
246
|
-
Use `excludedIndexKeys` when:
|
|
247
|
-
1. Working with file upload APIs that expect multiple files with the same key
|
|
248
|
-
2. Dealing with legacy APIs that don't support indexed form fields
|
|
249
|
-
3. Implementing multi-file upload where the server expects a flat structure
|
|
250
|
-
4. Handling file arrays where order doesn't matter
|
|
251
|
-
|
|
252
|
-
### useGlobalInfiniteQuery
|
|
253
|
-
|
|
254
|
-
A custom hook for handling infinite scroll or pagination scenarios.
|
|
255
|
-
|
|
256
|
-
#### Features
|
|
257
|
-
- Automatic pagination handling
|
|
258
|
-
- Built-in cache management
|
|
259
|
-
- Total count tracking
|
|
260
|
-
- Next page detection
|
|
261
|
-
|
|
262
|
-
#### Basic Usage
|
|
263
|
-
|
|
264
|
-
```javascript
|
|
265
|
-
const {
|
|
266
|
-
queryData,
|
|
267
|
-
isLoading,
|
|
268
|
-
isError,
|
|
269
|
-
error,
|
|
270
|
-
fetchNextPage,
|
|
271
|
-
hasNextPage,
|
|
272
|
-
totalCount
|
|
273
|
-
} = useGlobalInfiniteQuery({
|
|
274
|
-
url: '/api/posts',
|
|
275
|
-
queryKey: ['posts'],
|
|
276
|
-
methodType: 'GET',
|
|
277
|
-
data: { limit: 10 }
|
|
278
|
-
});
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
### useCookie
|
|
282
|
-
|
|
283
|
-
A utility hook for managing cookies across the application.
|
|
284
|
-
|
|
285
|
-
#### Features
|
|
286
|
-
- Simple cookie management
|
|
287
|
-
- Type-safe cookie operations
|
|
288
|
-
- Easy integration with authentication
|
|
289
|
-
|
|
290
|
-
#### Basic Usage
|
|
291
|
-
|
|
292
|
-
```javascript
|
|
293
|
-
const { cookie, setCookie, removeCookie } = useCookie({
|
|
294
|
-
cookieName: 'accessToken'
|
|
295
|
-
});
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
## API Reference
|
|
299
|
-
|
|
300
|
-
### useGlobalQuery Options
|
|
301
|
-
|
|
302
|
-
| Option | Type | Default | Description |
|
|
303
|
-
|--------|------|---------|-------------|
|
|
304
|
-
| url | string | required | API endpoint URL |
|
|
305
|
-
| queryKey | string[] | required | Unique key for caching |
|
|
306
|
-
| methodType | string | required | HTTP method (GET, POST, etc.) |
|
|
307
|
-
| data | object | optional | Request payload |
|
|
308
|
-
| enabled | boolean | true | Whether to enable the query |
|
|
309
|
-
| cacheTime | number | 300000 | Cache duration in ms |
|
|
310
|
-
| staleTime | number | 300000 | Stale data duration in ms |
|
|
311
|
-
|
|
312
|
-
### useGlobalMutation Options
|
|
313
|
-
|
|
314
|
-
| Option | Type | Default | Description |
|
|
315
|
-
|--------|------|---------|-------------|
|
|
316
|
-
| url | string | required | API endpoint URL |
|
|
317
|
-
| queriesToInvalidate | string[] | required | Queries to refresh after mutation |
|
|
318
|
-
| methodType | string | required | HTTP method (POST, PUT, DELETE) |
|
|
319
|
-
| data | object | optional | Default mutation data |
|
|
320
|
-
| isFormData | boolean | false | Whether to handle as FormData |
|
|
321
|
-
| closePopup | function | optional | Callback after success |
|
|
322
|
-
| excludedIndexKeys | string[] | optional | Keys to exclude from FormData indices |
|
|
323
|
-
|
|
324
|
-
### useGlobalInfiniteQuery Options
|
|
325
|
-
|
|
326
|
-
| Option | Type | Default | Description |
|
|
327
|
-
|--------|------|---------|-------------|
|
|
328
|
-
| url | string | required | API endpoint URL |
|
|
329
|
-
| queryKey | string[] | required | Unique key for caching |
|
|
330
|
-
| methodType | string | required | HTTP method |
|
|
331
|
-
| data | object | optional | Additional query parameters |
|
|
332
|
-
| enabled | boolean | true | Whether to enable the query |
|
|
333
|
-
| cacheTime | number | 300000 | Cache duration in ms |
|
|
334
|
-
| staleTime | number | 300000 | Stale data duration in ms |
|
|
335
|
-
|
|
336
|
-
## Best Practices
|
|
337
|
-
|
|
338
|
-
1. Always provide unique and descriptive query keys
|
|
339
|
-
2. Set appropriate cache and stale times based on data volatility
|
|
340
|
-
3. Handle loading and error states in your UI
|
|
341
|
-
4. Use the refetchQuery function for manual data refresh
|
|
342
|
-
5. Implement proper error boundaries in your application
|
|
343
|
-
|
|
344
|
-
## Contributing
|
|
345
|
-
|
|
346
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
347
|
-
|
|
348
|
-
## License
|
|
349
|
-
|
|
1
|
+
# Query Harbor
|
|
2
|
+
|
|
3
|
+
A collection of custom React hooks built on top of TanStack Query (formerly React Query) for handling API requests, mutations, and cookie management. These hooks provide a standardized way to handle data fetching, caching, and state management in React applications.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Hooks Overview](#hooks-overview)
|
|
9
|
+
- [useGlobalQuery](#useglobalquery)
|
|
10
|
+
- [useGlobalMutation](#useglobalmutation)
|
|
11
|
+
- [useGlobalInfiniteQuery](#useglobalinfinitequery)
|
|
12
|
+
- [useCookie](#usecookie)
|
|
13
|
+
- [Usage Examples](#usage-examples)
|
|
14
|
+
- [API Reference](#api-reference)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install required dependencies
|
|
20
|
+
npm install @tanstack/react-query react-cookie axios
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Hooks Overview
|
|
24
|
+
|
|
25
|
+
### useGlobalQuery
|
|
26
|
+
|
|
27
|
+
A custom hook for making standard API requests with built-in caching and state management.
|
|
28
|
+
|
|
29
|
+
#### Features
|
|
30
|
+
- Automatic authentication header handling
|
|
31
|
+
- Configurable cache and stale times
|
|
32
|
+
- Built-in error handling
|
|
33
|
+
- Query invalidation support
|
|
34
|
+
|
|
35
|
+
#### Basic Usage
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const {
|
|
39
|
+
queryData,
|
|
40
|
+
isLoading,
|
|
41
|
+
isError,
|
|
42
|
+
error,
|
|
43
|
+
refetchQuery
|
|
44
|
+
} = useGlobalQuery({
|
|
45
|
+
url: '/api/users',
|
|
46
|
+
queryKey: ['users'],
|
|
47
|
+
methodType: 'GET'
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### useGlobalMutation
|
|
52
|
+
|
|
53
|
+
A custom hook for handling data mutations (create, update, delete operations) with support for FormData.
|
|
54
|
+
|
|
55
|
+
#### Features
|
|
56
|
+
- FormData support with nested object handling
|
|
57
|
+
- Automatic query invalidation after successful mutation
|
|
58
|
+
- Priority data support
|
|
59
|
+
- Built-in error handling
|
|
60
|
+
|
|
61
|
+
#### Basic Usage
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const {
|
|
65
|
+
runMutation,
|
|
66
|
+
mutationLoading,
|
|
67
|
+
mutationData,
|
|
68
|
+
mutationError,
|
|
69
|
+
isMutationSucceeded
|
|
70
|
+
} = useGlobalMutation({
|
|
71
|
+
url: '/api/users',
|
|
72
|
+
queriesToInvalidate: ['users'],
|
|
73
|
+
methodType: 'POST',
|
|
74
|
+
data: userData
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### FormData Upload Examples
|
|
79
|
+
|
|
80
|
+
##### Basic FormData Upload
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
const {
|
|
84
|
+
runMutation,
|
|
85
|
+
mutationLoading
|
|
86
|
+
} = useGlobalMutation({
|
|
87
|
+
url: '/api/upload',
|
|
88
|
+
queriesToInvalidate: ['files'],
|
|
89
|
+
methodType: 'POST',
|
|
90
|
+
isFormData: true,
|
|
91
|
+
data: {
|
|
92
|
+
file: fileObject,
|
|
93
|
+
title: 'My Document'
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
##### Complex FormData with Arrays
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// Without excludedIndexKeys
|
|
102
|
+
const data = {
|
|
103
|
+
files: [file1, file2],
|
|
104
|
+
metadata: {
|
|
105
|
+
titles: ['Doc 1', 'Doc 2']
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// This will generate FormData with structure:
|
|
110
|
+
// files[0] = file1
|
|
111
|
+
// files[1] = file2
|
|
112
|
+
// metadata[titles][0] = Doc 1
|
|
113
|
+
// metadata[titles][1] = Doc 2
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
##### Using excludedIndexKeys
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
const MultipleFileUpload = () => {
|
|
120
|
+
const {
|
|
121
|
+
runMutation,
|
|
122
|
+
mutationLoading
|
|
123
|
+
} = useGlobalMutation({
|
|
124
|
+
url: '/api/upload-multiple',
|
|
125
|
+
queriesToInvalidate: ['files'],
|
|
126
|
+
methodType: 'POST',
|
|
127
|
+
isFormData: true,
|
|
128
|
+
// Specify which keys should not include array indices
|
|
129
|
+
excludedIndexKeys: ['files', 'documents'],
|
|
130
|
+
data: {
|
|
131
|
+
files: [file1, file2, file3],
|
|
132
|
+
documents: [docFile1, docFile2],
|
|
133
|
+
metadata: {
|
|
134
|
+
titles: ['Doc 1', 'Doc 2', 'Doc 3'],
|
|
135
|
+
categories: ['Cat 1', 'Cat 2', 'Cat 3']
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<button onClick={() => runMutation()}>
|
|
142
|
+
Upload Files
|
|
143
|
+
</button>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The above example will generate FormData with the following structure:
|
|
149
|
+
```plaintext
|
|
150
|
+
// Keys with excludedIndexKeys:
|
|
151
|
+
files = file1
|
|
152
|
+
files = file2
|
|
153
|
+
files = file3
|
|
154
|
+
documents = docFile1
|
|
155
|
+
documents = docFile2
|
|
156
|
+
|
|
157
|
+
// Regular array keys (maintain indices):
|
|
158
|
+
metadata[titles][0] = Doc 1
|
|
159
|
+
metadata[titles][1] = Doc 2
|
|
160
|
+
metadata[titles][2] = Doc 3
|
|
161
|
+
metadata[categories][0] = Cat 1
|
|
162
|
+
metadata[categories][1] = Cat 2
|
|
163
|
+
metadata[categories][2] = Cat 3
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
##### Real-World Example: Multiple File Upload with Metadata
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
const DocumentUploadForm = () => {
|
|
170
|
+
const [files, setFiles] = useState([]);
|
|
171
|
+
const [metadata, setMetadata] = useState({
|
|
172
|
+
department: 'HR',
|
|
173
|
+
tags: ['confidential', 'employee'],
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const {
|
|
177
|
+
runMutation,
|
|
178
|
+
mutationLoading,
|
|
179
|
+
isMutationSucceeded
|
|
180
|
+
} = useGlobalMutation({
|
|
181
|
+
url: '/api/documents/upload',
|
|
182
|
+
queriesToInvalidate: ['documents'],
|
|
183
|
+
methodType: 'POST',
|
|
184
|
+
isFormData: true,
|
|
185
|
+
excludedIndexKeys: ['files'], // files will be sent without indices
|
|
186
|
+
data: {
|
|
187
|
+
files: files,
|
|
188
|
+
metadata: metadata,
|
|
189
|
+
timestamp: new Date().toISOString(),
|
|
190
|
+
user: {
|
|
191
|
+
id: currentUserId,
|
|
192
|
+
role: userRole
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const handleFileChange = (e) => {
|
|
198
|
+
setFiles(Array.from(e.target.files));
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const handleUpload = () => {
|
|
202
|
+
runMutation();
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<div>
|
|
207
|
+
<input
|
|
208
|
+
type="file"
|
|
209
|
+
multiple
|
|
210
|
+
onChange={handleFileChange}
|
|
211
|
+
/>
|
|
212
|
+
{mutationLoading ? (
|
|
213
|
+
<p>Uploading...</p>
|
|
214
|
+
) : (
|
|
215
|
+
<button onClick={handleUpload}>
|
|
216
|
+
Upload Documents
|
|
217
|
+
</button>
|
|
218
|
+
)}
|
|
219
|
+
{isMutationSucceeded && (
|
|
220
|
+
<p>Upload completed successfully!</p>
|
|
221
|
+
)}
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
This will generate FormData where:
|
|
228
|
+
- Multiple files are sent with the same key name ('files')
|
|
229
|
+
- Metadata is properly nested with array indices preserved
|
|
230
|
+
- Additional data is structured appropriately
|
|
231
|
+
|
|
232
|
+
The resulting FormData structure will be:
|
|
233
|
+
```plaintext
|
|
234
|
+
files = File1
|
|
235
|
+
files = File2
|
|
236
|
+
metadata[department] = HR
|
|
237
|
+
metadata[tags][0] = confidential
|
|
238
|
+
metadata[tags][1] = employee
|
|
239
|
+
timestamp = 2024-02-23T10:00:00.000Z
|
|
240
|
+
user[id] = 123
|
|
241
|
+
user[role] = admin
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### When to Use excludedIndexKeys
|
|
245
|
+
|
|
246
|
+
Use `excludedIndexKeys` when:
|
|
247
|
+
1. Working with file upload APIs that expect multiple files with the same key
|
|
248
|
+
2. Dealing with legacy APIs that don't support indexed form fields
|
|
249
|
+
3. Implementing multi-file upload where the server expects a flat structure
|
|
250
|
+
4. Handling file arrays where order doesn't matter
|
|
251
|
+
|
|
252
|
+
### useGlobalInfiniteQuery
|
|
253
|
+
|
|
254
|
+
A custom hook for handling infinite scroll or pagination scenarios.
|
|
255
|
+
|
|
256
|
+
#### Features
|
|
257
|
+
- Automatic pagination handling
|
|
258
|
+
- Built-in cache management
|
|
259
|
+
- Total count tracking
|
|
260
|
+
- Next page detection
|
|
261
|
+
|
|
262
|
+
#### Basic Usage
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
const {
|
|
266
|
+
queryData,
|
|
267
|
+
isLoading,
|
|
268
|
+
isError,
|
|
269
|
+
error,
|
|
270
|
+
fetchNextPage,
|
|
271
|
+
hasNextPage,
|
|
272
|
+
totalCount
|
|
273
|
+
} = useGlobalInfiniteQuery({
|
|
274
|
+
url: '/api/posts',
|
|
275
|
+
queryKey: ['posts'],
|
|
276
|
+
methodType: 'GET',
|
|
277
|
+
data: { limit: 10 }
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### useCookie
|
|
282
|
+
|
|
283
|
+
A utility hook for managing cookies across the application.
|
|
284
|
+
|
|
285
|
+
#### Features
|
|
286
|
+
- Simple cookie management
|
|
287
|
+
- Type-safe cookie operations
|
|
288
|
+
- Easy integration with authentication
|
|
289
|
+
|
|
290
|
+
#### Basic Usage
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
const { cookie, setCookie, removeCookie } = useCookie({
|
|
294
|
+
cookieName: 'accessToken'
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## API Reference
|
|
299
|
+
|
|
300
|
+
### useGlobalQuery Options
|
|
301
|
+
|
|
302
|
+
| Option | Type | Default | Description |
|
|
303
|
+
|--------|------|---------|-------------|
|
|
304
|
+
| url | string | required | API endpoint URL |
|
|
305
|
+
| queryKey | string[] | required | Unique key for caching |
|
|
306
|
+
| methodType | string | required | HTTP method (GET, POST, etc.) |
|
|
307
|
+
| data | object | optional | Request payload |
|
|
308
|
+
| enabled | boolean | true | Whether to enable the query |
|
|
309
|
+
| cacheTime | number | 300000 | Cache duration in ms |
|
|
310
|
+
| staleTime | number | 300000 | Stale data duration in ms |
|
|
311
|
+
|
|
312
|
+
### useGlobalMutation Options
|
|
313
|
+
|
|
314
|
+
| Option | Type | Default | Description |
|
|
315
|
+
|--------|------|---------|-------------|
|
|
316
|
+
| url | string | required | API endpoint URL |
|
|
317
|
+
| queriesToInvalidate | string[] | required | Queries to refresh after mutation |
|
|
318
|
+
| methodType | string | required | HTTP method (POST, PUT, DELETE) |
|
|
319
|
+
| data | object | optional | Default mutation data |
|
|
320
|
+
| isFormData | boolean | false | Whether to handle as FormData |
|
|
321
|
+
| closePopup | function | optional | Callback after success |
|
|
322
|
+
| excludedIndexKeys | string[] | optional | Keys to exclude from FormData indices |
|
|
323
|
+
|
|
324
|
+
### useGlobalInfiniteQuery Options
|
|
325
|
+
|
|
326
|
+
| Option | Type | Default | Description |
|
|
327
|
+
|--------|------|---------|-------------|
|
|
328
|
+
| url | string | required | API endpoint URL |
|
|
329
|
+
| queryKey | string[] | required | Unique key for caching |
|
|
330
|
+
| methodType | string | required | HTTP method |
|
|
331
|
+
| data | object | optional | Additional query parameters |
|
|
332
|
+
| enabled | boolean | true | Whether to enable the query |
|
|
333
|
+
| cacheTime | number | 300000 | Cache duration in ms |
|
|
334
|
+
| staleTime | number | 300000 | Stale data duration in ms |
|
|
335
|
+
|
|
336
|
+
## Best Practices
|
|
337
|
+
|
|
338
|
+
1. Always provide unique and descriptive query keys
|
|
339
|
+
2. Set appropriate cache and stale times based on data volatility
|
|
340
|
+
3. Handle loading and error states in your UI
|
|
341
|
+
4. Use the refetchQuery function for manual data refresh
|
|
342
|
+
5. Implement proper error boundaries in your application
|
|
343
|
+
|
|
344
|
+
## Contributing
|
|
345
|
+
|
|
346
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
347
|
+
|
|
348
|
+
## License
|
|
349
|
+
|
|
350
350
|
MIT
|