@ahoo-wang/fetcher-react 3.5.8 → 3.6.1

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.
Files changed (75) hide show
  1. package/README.md +868 -609
  2. package/README.zh-CN.md +2079 -672
  3. package/dist/core/debounced/index.d.ts +4 -0
  4. package/dist/core/debounced/index.d.ts.map +1 -0
  5. package/dist/core/debounced/useDebouncedCallback.d.ts.map +1 -0
  6. package/dist/core/{useDebouncedExecutePromise.d.ts → debounced/useDebouncedExecutePromise.d.ts} +1 -1
  7. package/dist/core/debounced/useDebouncedExecutePromise.d.ts.map +1 -0
  8. package/dist/{wow/debounce → core/debounced}/useDebouncedQuery.d.ts +1 -2
  9. package/dist/core/debounced/useDebouncedQuery.d.ts.map +1 -0
  10. package/dist/core/index.d.ts +3 -2
  11. package/dist/core/index.d.ts.map +1 -1
  12. package/dist/{wow → core}/useQuery.d.ts +3 -3
  13. package/dist/core/useQuery.d.ts.map +1 -0
  14. package/dist/{wow → core}/useQueryState.d.ts +2 -2
  15. package/dist/core/useQueryState.d.ts.map +1 -0
  16. package/dist/cosec/useSecurity.d.ts +1 -1
  17. package/dist/fetcher/debounced/index.d.ts +3 -0
  18. package/dist/fetcher/debounced/index.d.ts.map +1 -0
  19. package/dist/fetcher/{useDebouncedFetcher.d.ts → debounced/useDebouncedFetcher.d.ts} +2 -2
  20. package/dist/fetcher/debounced/useDebouncedFetcher.d.ts.map +1 -0
  21. package/dist/{wow/debounce → fetcher/debounced}/useDebouncedFetcherQuery.d.ts +1 -1
  22. package/dist/fetcher/debounced/useDebouncedFetcherQuery.d.ts.map +1 -0
  23. package/dist/fetcher/index.d.ts +2 -1
  24. package/dist/fetcher/index.d.ts.map +1 -1
  25. package/dist/{wow → fetcher}/useFetcherQuery.d.ts +4 -4
  26. package/dist/fetcher/useFetcherQuery.d.ts.map +1 -0
  27. package/dist/index.es.js +573 -552
  28. package/dist/index.es.js.map +1 -1
  29. package/dist/index.umd.js +1 -1
  30. package/dist/index.umd.js.map +1 -1
  31. package/dist/types.d.ts +7 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/wow/fetcher/index.d.ts +6 -0
  34. package/dist/wow/fetcher/index.d.ts.map +1 -0
  35. package/dist/wow/{useFetcherCountQuery.d.ts → fetcher/useFetcherCountQuery.d.ts} +2 -2
  36. package/dist/wow/fetcher/useFetcherCountQuery.d.ts.map +1 -0
  37. package/dist/wow/{useFetcherListQuery.d.ts → fetcher/useFetcherListQuery.d.ts} +2 -2
  38. package/dist/wow/fetcher/useFetcherListQuery.d.ts.map +1 -0
  39. package/dist/wow/{useFetcherListStreamQuery.d.ts → fetcher/useFetcherListStreamQuery.d.ts} +2 -2
  40. package/dist/wow/fetcher/useFetcherListStreamQuery.d.ts.map +1 -0
  41. package/dist/wow/{useFetcherPagedQuery.d.ts → fetcher/useFetcherPagedQuery.d.ts} +2 -2
  42. package/dist/wow/fetcher/useFetcherPagedQuery.d.ts.map +1 -0
  43. package/dist/wow/{useFetcherSingleQuery.d.ts → fetcher/useFetcherSingleQuery.d.ts} +2 -2
  44. package/dist/wow/fetcher/useFetcherSingleQuery.d.ts.map +1 -0
  45. package/dist/wow/index.d.ts +1 -10
  46. package/dist/wow/index.d.ts.map +1 -1
  47. package/dist/wow/useCountQuery.d.ts +1 -1
  48. package/dist/wow/useCountQuery.d.ts.map +1 -1
  49. package/dist/wow/useListQuery.d.ts +1 -1
  50. package/dist/wow/useListQuery.d.ts.map +1 -1
  51. package/dist/wow/useListStreamQuery.d.ts +1 -1
  52. package/dist/wow/useListStreamQuery.d.ts.map +1 -1
  53. package/dist/wow/usePagedQuery.d.ts +1 -1
  54. package/dist/wow/usePagedQuery.d.ts.map +1 -1
  55. package/dist/wow/useSingleQuery.d.ts +1 -1
  56. package/dist/wow/useSingleQuery.d.ts.map +1 -1
  57. package/package.json +2 -2
  58. package/dist/core/useDebouncedCallback.d.ts.map +0 -1
  59. package/dist/core/useDebouncedExecutePromise.d.ts.map +0 -1
  60. package/dist/fetcher/useDebouncedFetcher.d.ts.map +0 -1
  61. package/dist/wow/debounce/index.d.ts +0 -3
  62. package/dist/wow/debounce/index.d.ts.map +0 -1
  63. package/dist/wow/debounce/useDebouncedFetcherQuery.d.ts.map +0 -1
  64. package/dist/wow/debounce/useDebouncedQuery.d.ts.map +0 -1
  65. package/dist/wow/types.d.ts +0 -7
  66. package/dist/wow/types.d.ts.map +0 -1
  67. package/dist/wow/useFetcherCountQuery.d.ts.map +0 -1
  68. package/dist/wow/useFetcherListQuery.d.ts.map +0 -1
  69. package/dist/wow/useFetcherListStreamQuery.d.ts.map +0 -1
  70. package/dist/wow/useFetcherPagedQuery.d.ts.map +0 -1
  71. package/dist/wow/useFetcherQuery.d.ts.map +0 -1
  72. package/dist/wow/useFetcherSingleQuery.d.ts.map +0 -1
  73. package/dist/wow/useQuery.d.ts.map +0 -1
  74. package/dist/wow/useQueryState.d.ts.map +0 -1
  75. /package/dist/core/{useDebouncedCallback.d.ts → debounced/useDebouncedCallback.d.ts} +0 -0
package/README.md CHANGED
@@ -29,19 +29,25 @@ robust data fetching capabilities.
29
29
  - [Quick Start](#quick-start)
30
30
  - [Usage](#usage)
31
31
  - [Core Hooks](#core-hooks)
32
- - [useFetcher](#usefetcher-hook)
33
32
  - [useExecutePromise](#useexecutepromise-hook)
34
33
  - [usePromiseState](#usepromisestate-hook)
35
- - [Debounced Hooks](#debounced-hooks)
36
- - [useDebouncedCallback](#usedebouncedcallback)
37
- - [useDebouncedExecutePromise](#usedebouncedexecutepromise)
38
- - [useDebouncedFetcher](#usedebouncedfetcher)
39
- - [useDebouncedFetcherQuery](#usedebouncedfetcherquery)
40
- - [useDebouncedQuery](#usedebouncedquery)
41
- - [Utility Hooks](#utility-hooks)
42
34
  - [useRequestId](#userequestid-hook)
43
35
  - [useLatest](#uselatest-hook)
44
36
  - [useRefs](#userefs-hook)
37
+ - [useQuery](#usequery-hook)
38
+ - [useQueryState](#usequerystate-hook)
39
+ - [useMounted](#usemounted-hook)
40
+ - [useForceUpdate](#useforceupdate-hook)
41
+ - [Debounced Hooks](#debounced-hooks)
42
+ - [useDebouncedCallback](#usedebouncedcallback)
43
+ - [useDebouncedExecutePromise](#usedebouncedexecutepromise)
44
+ - [useDebouncedQuery](#usedebouncedquery)
45
+ - [Fetcher Hooks](#fetcher-hooks)
46
+ - [useFetcher](#usefetcher-hook)
47
+ - [useFetcherQuery](#usefetcherquery-hook)
48
+ - [Debounced Fetcher Hooks](#debounced-fetcher-hooks)
49
+ - [useDebouncedFetcher](#usedebouncedfetcher)
50
+ - [useDebouncedFetcherQuery](#usedebouncedfetcherquery)
45
51
  - [Storage Hooks](#storage-hooks)
46
52
  - [useKeyStorage](#usekeystorage-hook)
47
53
  - [useImmerKeyStorage](#useimmerkeystorage-hook)
@@ -51,20 +57,20 @@ robust data fetching capabilities.
51
57
  - [useSecurity](#usesecurity-hook)
52
58
  - [SecurityProvider](#securityprovider)
53
59
  - [useSecurityContext](#usesecuritycontext-hook)
60
+ - [RouteGuard](#routeguard)
54
61
  - [Wow Query Hooks](#wow-query-hooks)
55
- - [Basic Query Hooks](#basic-query-hooks)
56
- - [useListQuery](#uselistquery-hook)
57
- - [usePagedQuery](#usepagedquery-hook)
58
- - [useSingleQuery](#usesinglequery-hook)
59
- - [useCountQuery](#usecountquery-hook)
60
- - [Fetcher Query Hooks](#fetcher-query-hooks)
61
- - [useFetcherListQuery](#usefetcherlistquery-hook)
62
- - [useFetcherPagedQuery](#usefetcherpagedquery-hook)
63
- - [useFetcherSingleQuery](#usefetchersinglequery-hook)
64
- - [useFetcherCountQuery](#usefetchercountquery-hook)
65
- - [Stream Query Hooks](#stream-query-hooks)
66
- - [useListStreamQuery](#useliststreamquery-hook)
67
- - [useFetcherListStreamQuery](#usefetcherliststreamquery-hook)
62
+ - [Basic Query Hooks](#basic-query-hooks)
63
+ - [useListQuery](#uselistquery-hook)
64
+ - [usePagedQuery](#usepagedquery-hook)
65
+ - [useSingleQuery](#usesinglequery-hook)
66
+ - [useCountQuery](#usecountquery-hook)
67
+ - [useListStreamQuery](#useliststreamquery-hook)
68
+ - [Fetcher Query Hooks](#fetcher-query-hooks)
69
+ - [useFetcherListQuery](#usefetcherlistquery-hook)
70
+ - [useFetcherPagedQuery](#usefetcherpagedquery-hook)
71
+ - [useFetcherSingleQuery](#usefetchersinglequery-hook)
72
+ - [useFetcherCountQuery](#usefetchercountquery-hook)
73
+ - [useFetcherListStreamQuery](#usefetcherliststreamquery-hook)
68
74
  - [Best Practices](#best-practices)
69
75
  - [API Reference](#api-reference)
70
76
  - [License](#license)
@@ -107,269 +113,428 @@ function App() {
107
113
 
108
114
  ### Core Hooks
109
115
 
110
- #### useFetcher Hook
116
+ #### useExecutePromise Hook
111
117
 
112
- The `useFetcher` hook provides complete data fetching capabilities with automatic state management, race condition
113
- protection, and flexible configuration options. It includes built-in AbortController support inherited from `useExecutePromise`.
118
+ The `useExecutePromise` hook manages asynchronous operations with automatic state handling, built-in race condition
119
+ protection, and support for promise state options. It includes automatic AbortController support for canceling operations.
114
120
 
115
121
  ```typescript jsx
116
- import { useFetcher } from '@ahoo-wang/fetcher-react';
122
+ import { useExecutePromise } from '@ahoo-wang/fetcher-react';
117
123
 
118
124
  const MyComponent = () => {
119
- const { loading, error, result, execute, abort } = useFetcher<string>({
125
+ const { loading, result, error, execute, reset, abort } = useExecutePromise<string>({
120
126
  onAbort: () => {
121
- console.log('Fetch operation was aborted');
127
+ console.log('Operation was aborted');
122
128
  }
123
129
  });
124
130
 
131
+ const fetchData = async () => {
132
+ const response = await fetch('/api/data');
133
+ return response.text();
134
+ };
135
+
125
136
  const handleFetch = () => {
126
- execute({ url: '/api/users', method: 'GET' });
137
+ execute(fetchData); // Using a promise supplier
138
+ };
139
+
140
+ const handleDirectPromise = () => {
141
+ const promise = fetch('/api/data').then(res => res.text());
142
+ execute(promise); // Using a direct promise
127
143
  };
128
144
 
129
145
  const handleAbort = () => {
130
- abort(); // Cancel the current fetch operation
146
+ abort(); // Manually abort the current operation
131
147
  };
148
+
149
+ if (loading) return <div>Loading...</div>;
150
+ if (error) return <div>Error: {error.message}</div>;
151
+ return (
152
+ <div>
153
+ <button onClick={handleFetch}>Fetch with Supplier</button>
154
+ <button onClick={handleDirectPromise}>Fetch with Promise</button>
155
+ <button onClick={handleAbort} disabled={!loading}>Abort</button>
156
+ <button onClick={reset}>Reset</button>
157
+ {result && <p>{result}</p>}
158
+ </div>
159
+ );
160
+ };
132
161
  ```
133
162
 
134
- #### Auto Execute Example
163
+ ##### Abort Controller Support
164
+
165
+ The hook automatically creates an AbortController for each operation and provides methods to manage cancellation:
166
+
167
+ - **Automatic Cleanup**: Operations are automatically aborted when the component unmounts
168
+ - **Manual Abort**: Use the `abort()` method to cancel ongoing operations
169
+ - **onAbort Callback**: Configure a callback that fires when an operation is aborted (manually or automatically)
170
+ - **AbortController Access**: The AbortController is passed to promise suppliers for advanced cancellation handling
171
+
172
+ #### usePromiseState Hook
173
+
174
+ The `usePromiseState` hook provides state management for promise operations without execution logic. Supports both
175
+ static options and dynamic option suppliers.
135
176
 
136
177
  ```typescript jsx
137
- import { useListQuery } from '@ahoo-wang/fetcher-react';
178
+ import { usePromiseState, PromiseStatus } from '@ahoo-wang/fetcher-react';
138
179
 
139
180
  const MyComponent = () => {
140
- const { result, loading, error, execute, setCondition } = useListQuery({
141
- initialQuery: { condition: {}, projection: {}, sort: [], limit: 10 },
142
- list: async (listQuery) => fetchListData(listQuery),
143
- autoExecute: true, // Automatically execute on component mount
144
- });
145
-
146
- // The query will execute automatically when the component mounts
147
- // You can still manually trigger it with execute() or update conditions
181
+ const { status, loading, result, error, setSuccess, setError, setIdle } = usePromiseState<string>();
148
182
 
149
- if (loading) return <div>Loading...</div>;
150
- if (error) return <div>Error: {error.message}</div>;
183
+ const handleSuccess = () => setSuccess('Data loaded');
184
+ const handleError = () => setError(new Error('Failed to load'));
151
185
 
152
186
  return (
153
187
  <div>
154
- <ul>
155
- {result?.map((item, index) => (
156
- <li key={index}>{item.name}</li>
157
- ))}
158
- </ul>
188
+ <button onClick={handleSuccess}>Set Success</button>
189
+ <button onClick={handleError}>Set Error</button>
190
+ <button onClick={setIdle}>Reset</button>
191
+ <p>Status: {status}</p>
192
+ {loading && <p>Loading...</p>}
193
+ {result && <p>Result: {result}</p>}
194
+ {error && <p>Error: {error.message}</p>}
159
195
  </div>
160
196
  );
161
197
  };
162
198
  ```
163
199
 
164
- ### Debounced Hooks
200
+ ##### usePromiseState with Options Supplier
165
201
 
166
- 🚀 **Advanced Debouncing for React Applications** - Powerful hooks that combine debouncing with async operations, providing seamless rate limiting for API calls, user interactions, and promise execution.
202
+ ```typescript jsx
203
+ import { usePromiseState, PromiseStatus } from '@ahoo-wang/fetcher-react';
167
204
 
168
- #### useDebouncedCallback
205
+ const MyComponent = () => {
206
+ // Using options supplier for dynamic configuration
207
+ const optionsSupplier = () => ({
208
+ initialStatus: PromiseStatus.IDLE,
209
+ onSuccess: async (result: string) => {
210
+ await saveToAnalytics(result);
211
+ console.log('Success:', result);
212
+ },
213
+ onError: async (error) => {
214
+ await logErrorToServer(error);
215
+ console.error('Error:', error);
216
+ },
217
+ });
169
218
 
170
- A React hook that provides a debounced version of any callback function with leading/trailing edge execution options.
219
+ const { setSuccess, setError } = usePromiseState<string>(optionsSupplier);
220
+
221
+ return (
222
+ <div>
223
+ <button onClick={() => setSuccess('Dynamic success!')}>Set Success</button>
224
+ <button onClick={() => setError(new Error('Dynamic error!'))}>Set Error</button>
225
+ </div>
226
+ );
227
+ };
228
+ ```
229
+
230
+ #### useRequestId Hook
231
+
232
+ The `useRequestId` hook provides request ID management for preventing race conditions in async operations.
171
233
 
172
234
  ```typescript jsx
173
- import { useDebouncedCallback } from '@ahoo-wang/fetcher-react';
235
+ import { useRequestId } from '@ahoo-wang/fetcher-react';
174
236
 
175
- const SearchComponent = () => {
176
- const { run: debouncedSearch, cancel, isPending } = useDebouncedCallback(
177
- async (query: string) => {
178
- const response = await fetch(`/api/search?q=${query}`);
179
- const results = await response.json();
180
- console.log('Search results:', results);
181
- },
182
- { delay: 300 }
183
- );
237
+ const MyComponent = () => {
238
+ const { generate, isLatest, invalidate } = useRequestId();
184
239
 
185
- const handleSearch = (query: string) => {
186
- if (query.trim()) {
187
- debouncedSearch(query);
188
- } else {
189
- cancel(); // Cancel any pending search
240
+ const handleFetch = async () => {
241
+ const requestId = generate();
242
+
243
+ try {
244
+ const result = await fetchData();
245
+
246
+ if (isLatest(requestId)) {
247
+ setData(result);
248
+ }
249
+ } catch (error) {
250
+ if (isLatest(requestId)) {
251
+ setError(error);
252
+ }
190
253
  }
191
254
  };
192
255
 
193
256
  return (
194
257
  <div>
195
- <input
196
- type="text"
197
- placeholder="Search..."
198
- onChange={(e) => handleSearch(e.target.value)}
199
- />
200
- {isPending() && <div>Searching...</div>}
258
+ <button onClick={handleFetch}>Fetch Data</button>
259
+ <button onClick={invalidate}>Cancel Ongoing</button>
201
260
  </div>
202
261
  );
203
262
  };
204
263
  ```
205
264
 
206
- **Configuration Options:**
207
-
208
- - `delay`: Delay in milliseconds before execution (required, positive number)
209
- - `leading`: Execute immediately on first call (default: false)
210
- - `trailing`: Execute after delay on last call (default: true)
211
-
212
- #### useDebouncedExecutePromise
265
+ #### useLatest Hook
213
266
 
214
- Combines promise execution with debouncing functionality, perfect for API calls and async operations.
267
+ The `useLatest` hook returns a ref containing the latest value, useful for accessing the current value in async
268
+ callbacks.
215
269
 
216
270
  ```typescript jsx
217
- import { useDebouncedExecutePromise } from '@ahoo-wang/fetcher-react';
271
+ import { useLatest } from '@ahoo-wang/fetcher-react';
218
272
 
219
- const DataFetcher = () => {
220
- const { loading, result, error, run } = useDebouncedExecutePromise({
221
- debounce: { delay: 300 },
222
- });
273
+ const MyComponent = () => {
274
+ const [count, setCount] = useState(0);
275
+ const latestCount = useLatest(count);
223
276
 
224
- const handleLoadUser = (userId: string) => {
225
- run(async () => {
226
- const response = await fetch(`/api/users/${userId}`);
227
- return response.json();
228
- });
277
+ const handleAsync = async () => {
278
+ await someAsyncOperation();
279
+ console.log('Latest count:', latestCount.current); // Always the latest
229
280
  };
230
281
 
231
282
  return (
232
283
  <div>
233
- <button onClick={() => handleLoadUser('user123')}>
234
- Load User
235
- </button>
236
- {loading && <div>Loading...</div>}
237
- {error && <div>Error: {error.message}</div>}
238
- {result && <div>User: {result.name}</div>}
284
+ <p>Count: {count}</p>
285
+ <button onClick={() => setCount(c => c + 1)}>Increment</button>
286
+ <button onClick={handleAsync}>Async Log</button>
239
287
  </div>
240
288
  );
241
289
  };
242
290
  ```
243
291
 
244
- #### useDebouncedFetcher
292
+ #### useRefs Hook
245
293
 
246
- Specialized hook combining HTTP fetching with debouncing, built on top of the core fetcher library.
294
+ The `useRefs` hook provides a Map-like interface for managing multiple React refs dynamically. It allows registering, retrieving, and managing refs by key, with automatic cleanup on component unmount.
247
295
 
248
296
  ```typescript jsx
249
- import { useDebouncedFetcher } from '@ahoo-wang/fetcher-react';
297
+ import { useRefs } from '@ahoo-wang/fetcher-react';
250
298
 
251
- const SearchInput = () => {
252
- const [query, setQuery] = useState('');
253
- const { loading, result, error, run } = useDebouncedFetcher({
254
- debounce: { delay: 300 },
255
- onSuccess: (data) => {
256
- setSearchResults(data.results);
257
- }
258
- });
299
+ const MyComponent = () => {
300
+ const refs = useRefs<HTMLDivElement>();
259
301
 
260
- const handleChange = (value: string) => {
261
- setQuery(value);
262
- if (value.trim()) {
263
- run({
264
- url: '/api/search',
265
- method: 'GET',
266
- params: { q: value }
267
- });
268
- }
302
+ const handleFocus = (key: string) => {
303
+ const element = refs.get(key);
304
+ element?.focus();
269
305
  };
270
306
 
271
307
  return (
272
308
  <div>
273
- <input
274
- value={query}
275
- onChange={(e) => handleChange(e.target.value)}
276
- placeholder="Search..."
277
- />
278
- {loading && <div>Searching...</div>}
279
- {error && <div>Error: {error.message}</div>}
280
- {result && <SearchResults data={result} />}
309
+ <div ref={refs.register('first')} tabIndex={0}>First Element</div>
310
+ <div ref={refs.register('second')} tabIndex={0}>Second Element</div>
311
+ <button onClick={() => handleFocus('first')}>Focus First</button>
312
+ <button onClick={() => handleFocus('second')}>Focus Second</button>
281
313
  </div>
282
314
  );
283
315
  };
284
316
  ```
285
317
 
286
- **Debouncing Strategies:**
318
+ Key features:
287
319
 
288
- - **Leading Edge**: Execute immediately on first call, then debounce subsequent calls
289
- - **Trailing Edge**: Execute after delay on last call (default behavior)
290
- - **Leading + Trailing**: Execute immediately, then again after delay if called again
320
+ - **Dynamic Registration**: Register refs with string, number, or symbol keys
321
+ - **Map-like API**: Full Map interface with get, set, has, delete, etc.
322
+ - **Automatic Cleanup**: Refs are cleared when component unmounts
323
+ - **Type Safety**: Full TypeScript support for ref types
291
324
 
292
- #### useDebouncedFetcherQuery
325
+ #### useQuery Hook
293
326
 
294
- Combines query-based HTTP fetching with debouncing, perfect for search inputs and dynamic query scenarios where you want to debounce API calls based on query parameters.
327
+ The `useQuery` hook provides a complete solution for managing query-based asynchronous operations with automatic state management and execution control.
295
328
 
296
329
  ```typescript jsx
297
- import { useDebouncedFetcherQuery } from '@ahoo-wang/fetcher-react';
330
+ import { useQuery } from '@ahoo-wang/fetcher-react';
298
331
 
299
- interface SearchQuery {
300
- keyword: string;
301
- limit: number;
302
- filters?: { category?: string };
332
+ interface UserQuery {
333
+ id: string;
303
334
  }
304
335
 
305
- interface SearchResult {
306
- items: Array<{ id: string; title: string }>;
307
- total: number;
336
+ interface User {
337
+ id: string;
338
+ name: string;
308
339
  }
309
340
 
310
- const SearchComponent = () => {
311
- const {
312
- loading,
313
- result,
314
- error,
315
- run,
316
- cancel,
317
- isPending,
318
- setQuery,
319
- getQuery,
320
- } = useDebouncedFetcherQuery<SearchQuery, SearchResult>({
321
- url: '/api/search',
322
- initialQuery: { keyword: '', limit: 10 },
323
- debounce: { delay: 300 }, // Debounce for 300ms
324
- autoExecute: false, // Don't execute on mount
341
+ function UserComponent() {
342
+ const { loading, result, error, execute, setQuery } = useQuery<UserQuery, User>({
343
+ initialQuery: { id: '1' },
344
+ execute: async (query) => {
345
+ const response = await fetch(`/api/users/${query.id}`);
346
+ return response.json();
347
+ },
348
+ autoExecute: true,
325
349
  });
326
350
 
327
- const handleSearch = (keyword: string) => {
328
- setQuery({ keyword, limit: 10 }); // This will trigger debounced execution if autoExecute was true
351
+ const handleUserChange = (userId: string) => {
352
+ setQuery({ id: userId }); // Automatically executes if autoExecute is true
329
353
  };
330
354
 
331
- const handleManualSearch = () => {
332
- run(); // Manual debounced execution with current query
355
+ if (loading) return <div>Loading...</div>;
356
+ if (error) return <div>Error: {error.message}</div>;
357
+ return (
358
+ <div>
359
+ <button onClick={() => handleUserChange('2')}>Load User 2</button>
360
+ {result && <p>User: {result.name}</p>}
361
+ </div>
362
+ );
363
+ }
364
+ ```
365
+
366
+ #### useQueryState Hook
367
+
368
+ The `useQueryState` hook provides state management for query parameters with automatic execution capabilities.
369
+
370
+ ```typescript jsx
371
+ import { useQueryState } from '@ahoo-wang/fetcher-react';
372
+
373
+ interface UserQuery {
374
+ id: string;
375
+ name?: string;
376
+ }
377
+
378
+ function UserComponent() {
379
+ const executeQuery = async (query: UserQuery) => {
380
+ // Perform query execution logic here
381
+ console.log('Executing query:', query);
333
382
  };
334
383
 
335
- const handleCancel = () => {
336
- cancel(); // Cancel any pending debounced execution
384
+ const { getQuery, setQuery } = useQueryState<UserQuery>({
385
+ initialQuery: { id: '1' },
386
+ autoExecute: true,
387
+ execute: executeQuery,
388
+ });
389
+
390
+ const handleQueryChange = (newQuery: UserQuery) => {
391
+ setQuery(newQuery); // Will automatically execute if autoExecute is true
337
392
  };
338
393
 
339
- if (loading) return <div>Searching...</div>;
340
- if (error) return <div>Error: {error.message}</div>;
394
+ const currentQuery = getQuery(); // Get current query parameters
395
+
396
+ return (
397
+ <div>
398
+ <button onClick={() => handleQueryChange({ id: '2', name: 'John' })}>
399
+ Update Query
400
+ </button>
401
+ </div>
402
+ );
403
+ }
404
+ ```
405
+
406
+ #### useMounted Hook
407
+
408
+ The `useMounted` hook provides a way to check if a component is still mounted, useful for avoiding state updates on unmounted components.
409
+
410
+ ```typescript jsx
411
+ import { useMounted } from '@ahoo-wang/fetcher-react';
412
+
413
+ const MyComponent = () => {
414
+ const isMounted = useMounted();
415
+
416
+ const handleAsyncOperation = async () => {
417
+ const result = await someAsyncOperation();
418
+
419
+ // Check if component is still mounted before updating state
420
+ if (isMounted()) {
421
+ setData(result);
422
+ }
423
+ };
424
+
425
+ return (
426
+ <div>
427
+ <button onClick={handleAsyncOperation}>Perform Async Operation</button>
428
+ </div>
429
+ );
430
+ };
431
+ ```
432
+
433
+ #### useForceUpdate Hook
434
+
435
+ The `useForceUpdate` hook provides a way to force a component to re-render, useful when you need to trigger a render based on external changes.
436
+
437
+ ```typescript jsx
438
+ import { useForceUpdate } from '@ahoo-wang/fetcher-react';
439
+
440
+ const MyComponent = () => {
441
+ const forceUpdate = useForceUpdate();
442
+
443
+ const handleExternalChange = () => {
444
+ // Perform some external operation that doesn't trigger a re-render
445
+ updateExternalState();
446
+
447
+ // Force the component to re-render to reflect the changes
448
+ forceUpdate();
449
+ };
450
+
451
+ return (
452
+ <div>
453
+ <button onClick={handleExternalChange}>Force Update</button>
454
+ </div>
455
+ );
456
+ };
457
+ ```
458
+
459
+ ### Debounced Hooks
460
+
461
+ 🚀 **Advanced Debouncing for React Applications** - Powerful hooks that combine debouncing with async operations, providing seamless rate limiting for API calls, user interactions, and promise execution.
462
+
463
+ #### useDebouncedCallback
464
+
465
+ A React hook that provides a debounced version of any callback function with leading/trailing edge execution options.
466
+
467
+ ```typescript jsx
468
+ import { useDebouncedCallback } from '@ahoo-wang/fetcher-react';
469
+
470
+ const SearchComponent = () => {
471
+ const { run: debouncedSearch, cancel, isPending } = useDebouncedCallback(
472
+ async (query: string) => {
473
+ const response = await fetch(`/api/search?q=${query}`);
474
+ const results = await response.json();
475
+ console.log('Search results:', results);
476
+ },
477
+ { delay: 300 }
478
+ );
479
+
480
+ const handleSearch = (query: string) => {
481
+ if (query.trim()) {
482
+ debouncedSearch(query);
483
+ } else {
484
+ cancel(); // Cancel any pending search
485
+ }
486
+ };
341
487
 
342
488
  return (
343
489
  <div>
344
490
  <input
345
491
  type="text"
346
- onChange={(e) => handleSearch(e.target.value)}
347
492
  placeholder="Search..."
493
+ onChange={(e) => handleSearch(e.target.value)}
348
494
  />
349
- <button onClick={handleManualSearch} disabled={isPending()}>
350
- {isPending() ? 'Searching...' : 'Search'}
351
- </button>
352
- <button onClick={handleCancel}>Cancel</button>
353
- {result && (
354
- <div>
355
- Found {result.total} items:
356
- {result.items.map(item => (
357
- <div key={item.id}>{item.title}</div>
358
- ))}
359
- </div>
360
- )}
495
+ {isPending() && <div>Searching...</div>}
361
496
  </div>
362
497
  );
363
498
  };
364
499
  ```
365
500
 
366
- **Key Features:**
501
+ **Configuration Options:**
367
502
 
368
- - **Query State Management**: Automatic query parameter handling with `setQuery` and `getQuery`
369
- - **Debounced Execution**: Prevents excessive API calls during rapid user input
370
- - **Auto-Execution**: Optional automatic execution when query parameters change
371
- - **Manual Control**: `run()` for manual execution, `cancel()` for cancellation
372
- - **Pending State**: `isPending()` to check if a debounced call is queued
503
+ - `delay`: Delay in milliseconds before execution (required, positive number)
504
+ - `leading`: Execute immediately on first call (default: false)
505
+ - `trailing`: Execute after delay on last call (default: true)
506
+
507
+ #### useDebouncedExecutePromise
508
+
509
+ Combines promise execution with debouncing functionality, perfect for API calls and async operations.
510
+
511
+ ```typescript jsx
512
+ import { useDebouncedExecutePromise } from '@ahoo-wang/fetcher-react';
513
+
514
+ const DataFetcher = () => {
515
+ const { loading, result, error, run } = useDebouncedExecutePromise({
516
+ debounce: { delay: 300 },
517
+ });
518
+
519
+ const handleLoadUser = (userId: string) => {
520
+ run(async () => {
521
+ const response = await fetch(`/api/users/${userId}`);
522
+ return response.json();
523
+ });
524
+ };
525
+
526
+ return (
527
+ <div>
528
+ <button onClick={() => handleLoadUser('user123')}>
529
+ Load User
530
+ </button>
531
+ {loading && <div>Loading...</div>}
532
+ {error && <div>Error: {error.message}</div>}
533
+ {result && <div>User: {result.name}</div>}
534
+ </div>
535
+ );
536
+ };
537
+ ```
373
538
 
374
539
  #### useDebouncedQuery
375
540
 
@@ -461,382 +626,222 @@ const SearchComponent = () => {
461
626
  - **Pending State**: `isPending()` to check if a debounced call is queued
462
627
  - **Custom Execution**: Flexible execute function for any query operation
463
628
 
464
- ### useExecutePromise Hook
629
+ ### Fetcher Hooks
465
630
 
466
- The `useExecutePromise` hook manages asynchronous operations with automatic state handling, built-in race condition
467
- protection, and support for promise state options. It includes automatic AbortController support for canceling operations.
631
+ #### useFetcher Hook
632
+
633
+ The `useFetcher` hook provides complete data fetching capabilities with automatic state management, race condition
634
+ protection, and flexible configuration options. It includes built-in AbortController support inherited from `useExecutePromise`.
468
635
 
469
636
  ```typescript jsx
470
- import { useExecutePromise } from '@ahoo-wang/fetcher-react';
637
+ import { useFetcher } from '@ahoo-wang/fetcher-react';
471
638
 
472
639
  const MyComponent = () => {
473
- const { loading, result, error, execute, reset, abort } = useExecutePromise<string>({
640
+ const { loading, error, result, execute, abort } = useFetcher<string>({
474
641
  onAbort: () => {
475
- console.log('Operation was aborted');
642
+ console.log('Fetch operation was aborted');
476
643
  }
477
644
  });
478
645
 
479
- const fetchData = async () => {
480
- const response = await fetch('/api/data');
481
- return response.text();
482
- };
483
-
484
646
  const handleFetch = () => {
485
- execute(fetchData); // Using a promise supplier
486
- };
487
-
488
- const handleDirectPromise = () => {
489
- const promise = fetch('/api/data').then(res => res.text());
490
- execute(promise); // Using a direct promise
647
+ execute({ url: '/api/users', method: 'GET' });
491
648
  };
492
649
 
493
650
  const handleAbort = () => {
494
- abort(); // Manually abort the current operation
651
+ abort(); // Cancel the current fetch operation
495
652
  };
496
-
497
- if (loading) return <div>Loading...</div>;
498
- if (error) return <div>Error: {error.message}</div>;
499
- return (
500
- <div>
501
- <button onClick={handleFetch}>Fetch with Supplier</button>
502
- <button onClick={handleDirectPromise}>Fetch with Promise</button>
503
- <button onClick={handleAbort} disabled={!loading}>Abort</button>
504
- <button onClick={reset}>Reset</button>
505
- {result && <p>{result}</p>}
506
- </div>
507
- );
508
- };
509
653
  ```
510
654
 
511
- #### Abort Controller Support
512
-
513
- The hook automatically creates an AbortController for each operation and provides methods to manage cancellation:
514
-
515
- - **Automatic Cleanup**: Operations are automatically aborted when the component unmounts
516
- - **Manual Abort**: Use the `abort()` method to cancel ongoing operations
517
- - **onAbort Callback**: Configure a callback that fires when an operation is aborted (manually or automatically)
518
- - **AbortController Access**: The AbortController is passed to promise suppliers for advanced cancellation handling
519
-
520
- ### usePromiseState Hook
521
-
522
- The `usePromiseState` hook provides state management for promise operations without execution logic. Supports both
523
- static options and dynamic option suppliers.
524
-
525
- ```typescript jsx
526
- import { usePromiseState, PromiseStatus } from '@ahoo-wang/fetcher-react';
527
-
528
- const MyComponent = () => {
529
- const { status, loading, result, error, setSuccess, setError, setIdle } = usePromiseState<string>();
530
-
531
- const handleSuccess = () => setSuccess('Data loaded');
532
- const handleError = () => setError(new Error('Failed to load'));
533
-
534
- return (
535
- <div>
536
- <button onClick={handleSuccess}>Set Success</button>
537
- <button onClick={handleError}>Set Error</button>
538
- <button onClick={setIdle}>Reset</button>
539
- <p>Status: {status}</p>
540
- {loading && <p>Loading...</p>}
541
- {result && <p>Result: {result}</p>}
542
- {error && <p>Error: {error.message}</p>}
543
- </div>
544
- );
545
- };
546
- ```
547
-
548
- #### usePromiseState with Options Supplier
655
+ #### Auto Execute Example
549
656
 
550
657
  ```typescript jsx
551
- import { usePromiseState, PromiseStatus } from '@ahoo-wang/fetcher-react';
658
+ import { useListQuery } from '@ahoo-wang/fetcher-react';
552
659
 
553
660
  const MyComponent = () => {
554
- // Using options supplier for dynamic configuration
555
- const optionsSupplier = () => ({
556
- initialStatus: PromiseStatus.IDLE,
557
- onSuccess: async (result: string) => {
558
- await saveToAnalytics(result);
559
- console.log('Success:', result);
560
- },
561
- onError: async (error) => {
562
- await logErrorToServer(error);
563
- console.error('Error:', error);
564
- },
661
+ const { result, loading, error, execute, setCondition } = useListQuery({
662
+ initialQuery: { condition: {}, projection: {}, sort: [], limit: 10 },
663
+ list: async (listQuery) => fetchListData(listQuery),
664
+ autoExecute: true, // Automatically execute on component mount
565
665
  });
566
666
 
567
- const { setSuccess, setError } = usePromiseState<string>(optionsSupplier);
568
-
569
- return (
570
- <div>
571
- <button onClick={() => setSuccess('Dynamic success!')}>Set Success</button>
572
- <button onClick={() => setError(new Error('Dynamic error!'))}>Set Error</button>
573
- </div>
574
- );
575
- };
576
- ```
577
-
578
- ### Utility Hooks
579
-
580
- #### useRequestId Hook
581
-
582
- The `useRequestId` hook provides request ID management for preventing race conditions in async operations.
583
-
584
- ```typescript jsx
585
- import { useRequestId } from '@ahoo-wang/fetcher-react';
586
-
587
- const MyComponent = () => {
588
- const { generate, isLatest, invalidate } = useRequestId();
589
-
590
- const handleFetch = async () => {
591
- const requestId = generate();
592
-
593
- try {
594
- const result = await fetchData();
595
-
596
- if (isLatest(requestId)) {
597
- setData(result);
598
- }
599
- } catch (error) {
600
- if (isLatest(requestId)) {
601
- setError(error);
602
- }
603
- }
604
- };
605
-
606
- return (
607
- <div>
608
- <button onClick={handleFetch}>Fetch Data</button>
609
- <button onClick={invalidate}>Cancel Ongoing</button>
610
- </div>
611
- );
612
- };
613
- ```
614
-
615
- ### useLatest Hook
616
-
617
- The `useLatest` hook returns a ref containing the latest value, useful for accessing the current value in async
618
- callbacks.
619
-
620
- ```typescript jsx
621
- import { useLatest } from '@ahoo-wang/fetcher-react';
622
-
623
- const MyComponent = () => {
624
- const [count, setCount] = useState(0);
625
- const latestCount = useLatest(count);
667
+ // The query will execute automatically when the component mounts
668
+ // You can still manually trigger it with execute() or update conditions
626
669
 
627
- const handleAsync = async () => {
628
- await someAsyncOperation();
629
- console.log('Latest count:', latestCount.current); // Always the latest
630
- };
670
+ if (loading) return <div>Loading...</div>;
671
+ if (error) return <div>Error: {error.message}</div>;
631
672
 
632
673
  return (
633
674
  <div>
634
- <p>Count: {count}</p>
635
- <button onClick={() => setCount(c => c + 1)}>Increment</button>
636
- <button onClick={handleAsync}>Async Log</button>
675
+ <ul>
676
+ {result?.map((item, index) => (
677
+ <li key={index}>{item.name}</li>
678
+ ))}
679
+ </ul>
637
680
  </div>
638
681
  );
639
682
  };
640
683
  ```
641
684
 
642
- ### useRefs Hook
685
+ #### useFetcherQuery Hook
643
686
 
644
- The `useRefs` hook provides a Map-like interface for managing multiple React refs dynamically. It allows registering, retrieving, and managing refs by key, with automatic cleanup on component unmount.
687
+ The `useFetcherQuery` hook provides a foundation for building specialized query hooks that integrate with the Fetcher library.
645
688
 
646
689
  ```typescript jsx
647
- import { useRefs } from '@ahoo-wang/fetcher-react';
690
+ import { useFetcherQuery } from '@ahoo-wang/fetcher-react';
648
691
 
649
692
  const MyComponent = () => {
650
- const refs = useRefs<HTMLDivElement>();
693
+ const { data, loading, error, execute } = useFetcherQuery({
694
+ url: '/api/data',
695
+ initialQuery: { /* query parameters */ },
696
+ execute: async (query) => {
697
+ // Custom execution logic
698
+ return fetchData(query);
699
+ },
700
+ autoExecute: true,
701
+ });
651
702
 
652
- const handleFocus = (key: string) => {
653
- const element = refs.get(key);
654
- element?.focus();
655
- };
703
+ if (loading) return <div>Loading...</div>;
704
+ if (error) return <div>Error: {error.message}</div>;
656
705
 
657
706
  return (
658
707
  <div>
659
- <div ref={refs.register('first')} tabIndex={0}>First Element</div>
660
- <div ref={refs.register('second')} tabIndex={0}>Second Element</div>
661
- <button onClick={() => handleFocus('first')}>Focus First</button>
662
- <button onClick={() => handleFocus('second')}>Focus Second</button>
708
+ <pre>{JSON.stringify(data, null, 2)}</pre>
663
709
  </div>
664
710
  );
665
711
  };
666
712
  ```
667
713
 
668
- Key features:
669
-
670
- - **Dynamic Registration**: Register refs with string, number, or symbol keys
671
- - **Map-like API**: Full Map interface with get, set, has, delete, etc.
672
- - **Automatic Cleanup**: Refs are cleared when component unmounts
673
- - **Type Safety**: Full TypeScript support for ref types
714
+ ### Debounced Fetcher Hooks
674
715
 
675
- ### Event Hooks
676
-
677
- #### useEventSubscription Hook
678
-
679
- The `useEventSubscription` hook provides a React interface for subscribing to typed event buses. It automatically manages subscription lifecycle while offering manual control functions for additional flexibility.
680
-
681
- ```typescript jsx
682
- import { useEventSubscription } from '@ahoo-wang/fetcher-react';
683
- import { eventBus } from './eventBus';
684
-
685
- function MyComponent() {
686
- const { subscribe, unsubscribe } = useEventSubscription({
687
- bus: eventBus,
688
- handler: {
689
- name: 'myEvent',
690
- handle: (event) => {
691
- console.log('Received event:', event);
692
- }
693
- }
694
- });
695
-
696
- // The hook automatically subscribes on mount and unsubscribes on unmount
697
- // You can also manually control subscription if needed
698
- const handleToggleSubscription = () => {
699
- if (someCondition) {
700
- subscribe();
701
- } else {
702
- unsubscribe();
703
- }
704
- };
705
-
706
- return <div>My Component</div>;
707
- }
708
- ```
709
-
710
- Key features:
711
-
712
- - **Automatic Lifecycle Management**: Automatically subscribes on component mount and unsubscribes on unmount
713
- - **Manual Control**: Provides `subscribe` and `unsubscribe` functions for additional control
714
- - **Type Safety**: Full TypeScript support with generic event types
715
- - **Error Handling**: Logs warnings for failed subscription attempts
716
- - **Event Bus Integration**: Works seamlessly with `@ahoo-wang/fetcher-eventbus` TypedEventBus instances
717
-
718
- ### CoSec Security Hooks
719
-
720
- 🛡️ **Enterprise Security Integration** - Powerful React hooks for managing authentication state with CoSec tokens, providing seamless integration with enterprise security systems and automatic token lifecycle management.
721
-
722
- #### useSecurity Hook
716
+ #### useDebouncedFetcher
723
717
 
724
- The `useSecurity` hook provides reactive access to authentication state and operations using CoSec tokens. It integrates with TokenStorage to persist tokens and updates state reactively when tokens change.
718
+ Specialized hook combining HTTP fetching with debouncing, built on top of the core fetcher library.
725
719
 
726
720
  ```typescript jsx
727
- import { useSecurity } from '@ahoo-wang/fetcher-react/cosec';
728
- import { tokenStorage } from './tokenStorage';
729
- import { useNavigate } from 'react-router-dom';
730
-
731
- function App() {
732
- const navigate = useNavigate();
721
+ import { useDebouncedFetcher } from '@ahoo-wang/fetcher-react';
733
722
 
734
- const { currentUser, authenticated, signIn, signOut } = useSecurity(tokenStorage, {
735
- onSignIn: () => {
736
- // Redirect to dashboard after successful login
737
- navigate('/dashboard');
738
- },
739
- onSignOut: () => {
740
- // Redirect to login page after logout
741
- navigate('/login');
723
+ const SearchInput = () => {
724
+ const [query, setQuery] = useState('');
725
+ const { loading, result, error, run } = useDebouncedFetcher({
726
+ debounce: { delay: 300 },
727
+ onSuccess: (data) => {
728
+ setSearchResults(data.results);
742
729
  }
743
730
  });
744
731
 
745
- const handleSignIn = async () => {
746
- // Direct token
747
- await signIn(compositeToken);
748
-
749
- // Or async function
750
- await signIn(async () => {
751
- const response = await fetch('/api/auth/login', {
752
- method: 'POST',
753
- body: JSON.stringify({ username, password })
732
+ const handleChange = (value: string) => {
733
+ setQuery(value);
734
+ if (value.trim()) {
735
+ run({
736
+ url: '/api/search',
737
+ method: 'GET',
738
+ params: { q: value }
754
739
  });
755
- return response.json();
756
- });
740
+ }
757
741
  };
758
742
 
759
- if (!authenticated) {
760
- return <button onClick={handleSignIn}>Sign In</button>;
761
- }
762
-
763
743
  return (
764
744
  <div>
765
- <p>Welcome, {currentUser.sub}!</p>
766
- <button onClick={signOut}>Sign Out</button>
745
+ <input
746
+ value={query}
747
+ onChange={(e) => handleChange(e.target.value)}
748
+ placeholder="Search..."
749
+ />
750
+ {loading && <div>Searching...</div>}
751
+ {error && <div>Error: {error.message}</div>}
752
+ {result && <SearchResults data={result} />}
767
753
  </div>
768
754
  );
769
- }
770
- ```
771
-
772
- **Key Features:**
773
-
774
- - **Reactive Authentication State**: Automatically updates when tokens change
775
- - **Flexible Sign-in Methods**: Supports both direct tokens and async token providers
776
- - **Lifecycle Callbacks**: Configurable callbacks for sign-in and sign-out events
777
- - **Type Safety**: Full TypeScript support with CoSec JWT payload types
778
- - **Token Persistence**: Integrates with TokenStorage for cross-session persistence
779
-
780
- #### SecurityProvider
781
-
782
- The `SecurityProvider` component wraps your application to provide authentication context through React context. It internally uses the `useSecurity` hook and makes authentication state available to all child components via the `useSecurityContext` hook.
783
-
784
- ```tsx
785
- import { SecurityProvider } from '@ahoo-wang/fetcher-react';
786
- import { tokenStorage } from './tokenStorage';
787
- import { useNavigate } from 'react-router-dom';
788
-
789
- function App() {
790
- const navigate = useNavigate();
791
-
792
- return (
793
- <SecurityProvider
794
- tokenStorage={tokenStorage}
795
- onSignIn={() => navigate('/dashboard')}
796
- onSignOut={() => navigate('/login')}
797
- >
798
- <MyApp />
799
- </SecurityProvider>
800
- );
801
- }
755
+ };
802
756
  ```
803
757
 
804
- **Configuration Options:**
758
+ **Debouncing Strategies:**
805
759
 
806
- - `tokenStorage`: TokenStorage instance for managing authentication tokens
807
- - `onSignIn`: Callback function invoked when sign in is successful
808
- - `onSignOut`: Callback function invoked when sign out occurs
809
- - `children`: Child components that will have access to security context
760
+ - **Leading Edge**: Execute immediately on first call, then debounce subsequent calls
761
+ - **Trailing Edge**: Execute after delay on last call (default behavior)
762
+ - **Leading + Trailing**: Execute immediately, then again after delay if called again
810
763
 
811
- #### useSecurityContext Hook
764
+ #### useDebouncedFetcherQuery
812
765
 
813
- The `useSecurityContext` hook provides access to authentication state and methods within components wrapped by `SecurityProvider`. It offers the same interface as `useSecurity` but through React context.
766
+ Combines query-based HTTP fetching with debouncing, perfect for search inputs and dynamic query scenarios where you want to debounce API calls based on query parameters.
814
767
 
815
- ```tsx
816
- import { useSecurityContext } from '@ahoo-wang/fetcher-react';
768
+ ```typescript jsx
769
+ import { useDebouncedFetcherQuery } from '@ahoo-wang/fetcher-react';
817
770
 
818
- function UserProfile() {
819
- const { currentUser, authenticated, signOut } = useSecurityContext();
771
+ interface SearchQuery {
772
+ keyword: string;
773
+ limit: number;
774
+ filters?: { category?: string };
775
+ }
820
776
 
821
- if (!authenticated) {
822
- return <div>Please sign in</div>;
823
- }
777
+ interface SearchResult {
778
+ items: Array<{ id: string; title: string }>;
779
+ total: number;
780
+ }
781
+
782
+ const SearchComponent = () => {
783
+ const {
784
+ loading,
785
+ result,
786
+ error,
787
+ run,
788
+ cancel,
789
+ isPending,
790
+ setQuery,
791
+ getQuery,
792
+ } = useDebouncedFetcherQuery<SearchQuery, SearchResult>({
793
+ url: '/api/search',
794
+ initialQuery: { keyword: '', limit: 10 },
795
+ debounce: { delay: 300 }, // Debounce for 300ms
796
+ autoExecute: false, // Don't execute on mount
797
+ });
798
+
799
+ const handleSearch = (keyword: string) => {
800
+ setQuery({ keyword, limit: 10 }); // This will trigger debounced execution if autoExecute was true
801
+ };
802
+
803
+ const handleManualSearch = () => {
804
+ run(); // Manual debounced execution with current query
805
+ };
806
+
807
+ const handleCancel = () => {
808
+ cancel(); // Cancel any pending debounced execution
809
+ };
810
+
811
+ if (loading) return <div>Searching...</div>;
812
+ if (error) return <div>Error: {error.message}</div>;
824
813
 
825
814
  return (
826
815
  <div>
827
- <p>Welcome, {currentUser.sub}!</p>
828
- <button onClick={signOut}>Sign Out</button>
816
+ <input
817
+ type="text"
818
+ onChange={(e) => handleSearch(e.target.value)}
819
+ placeholder="Search..."
820
+ />
821
+ <button onClick={handleManualSearch} disabled={isPending()}>
822
+ {isPending() ? 'Searching...' : 'Search'}
823
+ </button>
824
+ <button onClick={handleCancel}>Cancel</button>
825
+ {result && (
826
+ <div>
827
+ Found {result.total} items:
828
+ {result.items.map(item => (
829
+ <div key={item.id}>{item.title}</div>
830
+ ))}
831
+ </div>
832
+ )}
829
833
  </div>
830
834
  );
831
- }
835
+ };
832
836
  ```
833
837
 
834
- **Context Benefits:**
838
+ **Key Features:**
835
839
 
836
- - **Prop Drilling Elimination**: Access authentication state without passing props
837
- - **Component Isolation**: Components can access auth state regardless of component tree depth
838
- - **Centralized State**: Single source of truth for authentication across the application
839
- - **Automatic Re-rendering**: Components automatically re-render when authentication state changes
840
+ - **Query State Management**: Automatic query parameter handling with `setQuery` and `getQuery`
841
+ - **Debounced Execution**: Prevents excessive API calls during rapid user input
842
+ - **Auto-Execution**: Optional automatic execution when query parameters change
843
+ - **Manual Control**: `run()` for manual execution, `cancel()` for cancellation
844
+ - **Pending State**: `isPending()` to check if a debounced call is queued
840
845
 
841
846
  ### Storage Hooks
842
847
 
@@ -1167,22 +1172,188 @@ const prefsStorage = new KeyStorage<UserPreferences>({
1167
1172
  key: 'user-prefs',
1168
1173
  });
1169
1174
 
1170
- // TypeScript will catch invalid updates
1171
- const [prefs, updatePrefs] = useImmerKeyStorage(prefsStorage);
1175
+ // TypeScript will catch invalid updates
1176
+ const [prefs, updatePrefs] = useImmerKeyStorage(prefsStorage);
1177
+
1178
+ // This will cause a TypeScript error:
1179
+ // updatePrefs(draft => { draft.theme = 'invalid'; });
1180
+ ```
1181
+
1182
+ ### Event Hooks
1183
+
1184
+ #### useEventSubscription Hook
1185
+
1186
+ The `useEventSubscription` hook provides a React interface for subscribing to typed event buses. It automatically manages subscription lifecycle while offering manual control functions for additional flexibility.
1187
+
1188
+ ```typescript jsx
1189
+ import { useEventSubscription } from '@ahoo-wang/fetcher-react';
1190
+ import { eventBus } from './eventBus';
1191
+
1192
+ function MyComponent() {
1193
+ const { subscribe, unsubscribe } = useEventSubscription({
1194
+ bus: eventBus,
1195
+ handler: {
1196
+ name: 'myEvent',
1197
+ handle: (event) => {
1198
+ console.log('Received event:', event);
1199
+ }
1200
+ }
1201
+ });
1202
+
1203
+ // The hook automatically subscribes on mount and unsubscribes on unmount
1204
+ // You can also manually control subscription if needed
1205
+ const handleToggleSubscription = () => {
1206
+ if (someCondition) {
1207
+ subscribe();
1208
+ } else {
1209
+ unsubscribe();
1210
+ }
1211
+ };
1212
+
1213
+ return <div>My Component</div>;
1214
+ }
1215
+ ```
1216
+
1217
+ Key features:
1218
+
1219
+ - **Automatic Lifecycle Management**: Automatically subscribes on component mount and unsubscribes on unmount
1220
+ - **Manual Control**: Provides `subscribe` and `unsubscribe` functions for additional control
1221
+ - **Type Safety**: Full TypeScript support with generic event types
1222
+ - **Error Handling**: Logs warnings for failed subscription attempts
1223
+ - **Event Bus Integration**: Works seamlessly with `@ahoo-wang/fetcher-eventbus` TypedEventBus instances
1224
+
1225
+ ### CoSec Security Hooks
1226
+
1227
+ 🛡️ **Enterprise Security Integration** - Powerful React hooks for managing authentication state with CoSec tokens, providing seamless integration with enterprise security systems and automatic token lifecycle management.
1228
+
1229
+ #### useSecurity Hook
1230
+
1231
+ The `useSecurity` hook provides reactive access to authentication state and operations using CoSec tokens. It integrates with TokenStorage to persist tokens and updates state reactively when tokens change.
1232
+
1233
+ ```typescript jsx
1234
+ import { useSecurity } from '@ahoo-wang/fetcher-react';
1235
+ import { tokenStorage } from './tokenStorage';
1236
+ import { useNavigate } from 'react-router-dom';
1237
+
1238
+ function App() {
1239
+ const navigate = useNavigate();
1240
+
1241
+ const { currentUser, authenticated, signIn, signOut } = useSecurity(tokenStorage, {
1242
+ onSignIn: () => {
1243
+ // Redirect to dashboard after successful login
1244
+ navigate('/dashboard');
1245
+ },
1246
+ onSignOut: () => {
1247
+ // Redirect to login page after logout
1248
+ navigate('/login');
1249
+ }
1250
+ });
1251
+
1252
+ const handleSignIn = async () => {
1253
+ // Direct token
1254
+ await signIn(compositeToken);
1255
+
1256
+ // Or async function
1257
+ await signIn(async () => {
1258
+ const response = await fetch('/api/auth/login', {
1259
+ method: 'POST',
1260
+ body: JSON.stringify({ username, password })
1261
+ });
1262
+ return response.json();
1263
+ });
1264
+ };
1265
+
1266
+ if (!authenticated) {
1267
+ return <button onClick={handleSignIn}>Sign In</button>;
1268
+ }
1269
+
1270
+ return (
1271
+ <div>
1272
+ <p>Welcome, {currentUser.sub}!</p>
1273
+ <button onClick={signOut}>Sign Out</button>
1274
+ </div>
1275
+ );
1276
+ }
1277
+ ```
1278
+
1279
+ **Key Features:**
1280
+
1281
+ - **Reactive Authentication State**: Automatically updates when tokens change
1282
+ - **Flexible Sign-in Methods**: Supports both direct tokens and async token providers
1283
+ - **Lifecycle Callbacks**: Configurable callbacks for sign-in and sign-out events
1284
+ - **Type Safety**: Full TypeScript support with CoSec JWT payload types
1285
+ - **Token Persistence**: Integrates with TokenStorage for cross-session persistence
1286
+
1287
+ #### SecurityProvider
1288
+
1289
+ The `SecurityProvider` component wraps your application to provide authentication context through React context. It internally uses the `useSecurity` hook and makes authentication state available to all child components via the `useSecurityContext` hook.
1290
+
1291
+ ```tsx
1292
+ import { SecurityProvider } from '@ahoo-wang/fetcher-react';
1293
+ import { tokenStorage } from './tokenStorage';
1294
+ import { useNavigate } from 'react-router-dom';
1295
+
1296
+ function App() {
1297
+ const navigate = useNavigate();
1298
+
1299
+ return (
1300
+ <SecurityProvider
1301
+ tokenStorage={tokenStorage}
1302
+ onSignIn={() => navigate('/dashboard')}
1303
+ onSignOut={() => navigate('/login')}
1304
+ >
1305
+ <MyApp />
1306
+ </SecurityProvider>
1307
+ );
1308
+ }
1309
+ ```
1310
+
1311
+ **Configuration Options:**
1312
+
1313
+ - `tokenStorage`: TokenStorage instance for managing authentication tokens
1314
+ - `onSignIn`: Callback function invoked when sign in is successful
1315
+ - `onSignOut`: Callback function invoked when sign out occurs
1316
+ - `children`: Child components that will have access to security context
1317
+
1318
+ #### useSecurityContext Hook
1319
+
1320
+ The `useSecurityContext` hook provides access to authentication state and methods within components wrapped by `SecurityProvider`. It offers the same interface as `useSecurity` but through React context.
1321
+
1322
+ ```tsx
1323
+ import { useSecurityContext } from '@ahoo-wang/fetcher-react';
1324
+
1325
+ function UserProfile() {
1326
+ const { currentUser, authenticated, signOut } = useSecurityContext();
1327
+
1328
+ if (!authenticated) {
1329
+ return <div>Please sign in</div>;
1330
+ }
1331
+
1332
+ return (
1333
+ <div>
1334
+ <p>Welcome, {currentUser.sub}!</p>
1335
+ <button onClick={signOut}>Sign Out</button>
1336
+ </div>
1337
+ );
1338
+ }
1339
+ ```
1340
+
1341
+ **Context Benefits:**
1172
1342
 
1173
- // This will cause a TypeScript error:
1174
- // updatePrefs(draft => { draft.theme = 'invalid'; });
1175
- ```
1343
+ - **Prop Drilling Elimination**: Access authentication state without passing props
1344
+ - **Component Isolation**: Components can access auth state regardless of component tree depth
1345
+ - **Centralized State**: Single source of truth for authentication across the application
1346
+ - **Automatic Re-rendering**: Components automatically re-render when authentication state changes
1176
1347
 
1177
- ## Wow Query Hooks
1348
+ ### Wow Query Hooks
1178
1349
 
1179
1350
  The Wow Query Hooks provide advanced data querying capabilities with built-in state management for conditions,
1180
1351
  projections, sorting, pagination, and limits. These hooks are designed to work with the `@ahoo-wang/fetcher-wow` package
1181
1352
  for complex query operations.
1182
1353
 
1183
- ### Basic Query Hooks
1354
+ #### Basic Query Hooks
1184
1355
 
1185
- #### useListQuery Hook
1356
+ ##### useListQuery Hook
1186
1357
 
1187
1358
  The `useListQuery` hook manages list queries with state management for conditions, projections, sorting, and limits.
1188
1359
 
@@ -1219,7 +1390,7 @@ const MyComponent = () => {
1219
1390
  };
1220
1391
  ```
1221
1392
 
1222
- #### Auto Execute Example
1393
+ ##### Auto Execute Example
1223
1394
 
1224
1395
  ```typescript jsx
1225
1396
  import { useListQuery } from '@ahoo-wang/fetcher-react';
@@ -1249,7 +1420,7 @@ const MyComponent = () => {
1249
1420
  };
1250
1421
  ```
1251
1422
 
1252
- ### usePagedQuery Hook
1423
+ ##### usePagedQuery Hook
1253
1424
 
1254
1425
  The `usePagedQuery` hook manages paged queries with state management for conditions, projections, pagination, and
1255
1426
  sorting.
@@ -1297,7 +1468,7 @@ const MyComponent = () => {
1297
1468
  };
1298
1469
  ```
1299
1470
 
1300
- #### Auto Execute Example
1471
+ ###### Auto Execute Example
1301
1472
 
1302
1473
  ```typescript jsx
1303
1474
  import { usePagedQuery } from '@ahoo-wang/fetcher-react';
@@ -1337,7 +1508,7 @@ const MyComponent = () => {
1337
1508
  };
1338
1509
  ```
1339
1510
 
1340
- ### useSingleQuery Hook
1511
+ ##### useSingleQuery Hook
1341
1512
 
1342
1513
  The `useSingleQuery` hook manages single item queries with state management for conditions, projections, and sorting.
1343
1514
 
@@ -1370,7 +1541,7 @@ const MyComponent = () => {
1370
1541
  };
1371
1542
  ```
1372
1543
 
1373
- #### Auto Execute Example
1544
+ ###### Auto Execute Example
1374
1545
 
1375
1546
  ```typescript jsx
1376
1547
  import { useSingleQuery } from '@ahoo-wang/fetcher-react';
@@ -1395,7 +1566,7 @@ const MyComponent = () => {
1395
1566
  };
1396
1567
  ```
1397
1568
 
1398
- ### useCountQuery Hook
1569
+ ##### useCountQuery Hook
1399
1570
 
1400
1571
  The `useCountQuery` hook manages count queries with state management for conditions.
1401
1572
 
@@ -1428,7 +1599,7 @@ const MyComponent = () => {
1428
1599
  };
1429
1600
  ```
1430
1601
 
1431
- #### Auto Execute Example
1602
+ ###### Auto Execute Example
1432
1603
 
1433
1604
  ```typescript jsx
1434
1605
  import { useCountQuery } from '@ahoo-wang/fetcher-react';
@@ -1453,9 +1624,99 @@ const MyComponent = () => {
1453
1624
  };
1454
1625
  ```
1455
1626
 
1456
- ### Fetcher Query Hooks
1627
+ ##### useListStreamQuery Hook
1628
+
1629
+ The `useListStreamQuery` hook manages list stream queries that return a readable stream of server-sent events.
1630
+
1631
+ ```typescript jsx
1632
+ import { useListStreamQuery } from '@ahoo-wang/fetcher-react';
1633
+
1634
+ const MyComponent = () => {
1635
+ const { result, loading, error, execute, setCondition } = useListStreamQuery({
1636
+ initialQuery: { condition: {}, projection: {}, sort: [], limit: 100 },
1637
+ execute: async (listQuery) => {
1638
+ // Your stream fetching logic here
1639
+ return fetchListStream(listQuery);
1640
+ },
1641
+ });
1642
+
1643
+ useEffect(() => {
1644
+ if (result) {
1645
+ const reader = result.getReader();
1646
+ const readStream = async () => {
1647
+ try {
1648
+ while (true) {
1649
+ const { done, value } = await reader.read();
1650
+ if (done) break;
1651
+ console.log('Received:', value);
1652
+ // Process the stream event
1653
+ }
1654
+ } catch (error) {
1655
+ console.error('Stream error:', error);
1656
+ }
1657
+ };
1658
+ readStream();
1659
+ }
1660
+ }, [result]);
1661
+
1662
+ if (loading) return <div>Loading...</div>;
1663
+ if (error) return <div>Error: {error.message}</div>;
1664
+
1665
+ return (
1666
+ <div>
1667
+ <button onClick={execute}>Start Stream</button>
1668
+ </div>
1669
+ );
1670
+ };
1671
+ ```
1672
+
1673
+ ###### Auto Execute Example
1674
+
1675
+ ```typescript jsx
1676
+ import { useListStreamQuery } from '@ahoo-wang/fetcher-react';
1677
+
1678
+ const MyComponent = () => {
1679
+ const { result, loading, error, execute, setCondition } = useListStreamQuery({
1680
+ initialQuery: { condition: {}, projection: {}, sort: [], limit: 100 },
1681
+ execute: async (listQuery) => fetchListStream(listQuery),
1682
+ autoExecute: true, // Automatically execute on component mount
1683
+ });
1684
+
1685
+ useEffect(() => {
1686
+ if (result) {
1687
+ const reader = result.getReader();
1688
+ const readStream = async () => {
1689
+ try {
1690
+ while (true) {
1691
+ const { done, value } = await reader.read();
1692
+ if (done) break;
1693
+ console.log('Received:', value);
1694
+ // Process the stream event
1695
+ }
1696
+ } catch (error) {
1697
+ console.error('Stream error:', error);
1698
+ }
1699
+ };
1700
+ readStream();
1701
+ }
1702
+ }, [result]);
1703
+
1704
+ // The query will execute automatically when the component mounts
1705
+
1706
+ if (loading) return <div>Loading...</div>;
1707
+ if (error) return <div>Error: {error.message}</div>;
1708
+
1709
+ return (
1710
+ <div>
1711
+ {/* Stream is already started automatically */}
1712
+ </div>
1713
+ );
1714
+ };
1715
+ ```
1716
+
1717
+ #### Fetcher Query Hooks
1457
1718
 
1458
- #### useFetcherCountQuery Hook
1719
+ ##### useFetcherCountQuery Hook
1459
1720
 
1460
1721
  The `useFetcherCountQuery` hook is a specialized React hook for performing count queries using the Fetcher library. It is designed for scenarios where you need to retrieve the count of records that match a specific condition, returning a number representing the count.
1461
1722
 
@@ -1479,7 +1740,7 @@ function UserCountComponent() {
1479
1740
  }
1480
1741
  ```
1481
1742
 
1482
- #### Auto Execute Example
1743
+ ###### Auto Execute Example
1483
1744
 
1484
1745
  ```typescript jsx
1485
1746
  import { useFetcherCountQuery } from '@ahoo-wang/fetcher-react';
@@ -1500,7 +1761,7 @@ const MyComponent = () => {
1500
1761
  };
1501
1762
  ```
1502
1763
 
1503
- ### useFetcherPagedQuery Hook
1764
+ ##### useFetcherPagedQuery Hook
1504
1765
 
1505
1766
  The `useFetcherPagedQuery` hook is a specialized React hook for performing paged queries using the Fetcher library. It is designed for scenarios where you need to retrieve paginated data that matches a query condition, returning a PagedList containing the items for the current page along with pagination metadata.
1506
1767
 
@@ -1569,7 +1830,7 @@ function UserListComponent() {
1569
1830
  }
1570
1831
  ```
1571
1832
 
1572
- #### Auto Execute Example
1833
+ ###### Auto Execute Example
1573
1834
 
1574
1835
  ```typescript jsx
1575
1836
  import { useFetcherPagedQuery } from '@ahoo-wang/fetcher-react';
@@ -1605,7 +1866,7 @@ const MyComponent = () => {
1605
1866
  };
1606
1867
  ```
1607
1868
 
1608
- ### useFetcherListQuery Hook
1869
+ ##### useFetcherListQuery Hook
1609
1870
 
1610
1871
  The `useFetcherListQuery` hook is a specialized React hook for performing list queries using the Fetcher library. It is designed for fetching lists of items with support for filtering, sorting, and pagination through the ListQuery type, returning an array of results.
1611
1872
 
@@ -1666,7 +1927,7 @@ function UserListComponent() {
1666
1927
  }
1667
1928
  ```
1668
1929
 
1669
- #### Auto Execute Example
1930
+ ###### Auto Execute Example
1670
1931
 
1671
1932
  ```typescript jsx
1672
1933
  import { useFetcherListQuery } from '@ahoo-wang/fetcher-react';
@@ -1701,7 +1962,7 @@ const MyComponent = () => {
1701
1962
  };
1702
1963
  ```
1703
1964
 
1704
- ### useFetcherListStreamQuery Hook
1965
+ ##### useFetcherListStreamQuery Hook
1705
1966
 
1706
1967
  The `useFetcherListStreamQuery` hook is a specialized React hook for performing list stream queries using the Fetcher library with server-sent events. It is designed for scenarios where you need to retrieve a stream of data that matches a list query condition, returning a ReadableStream of JSON server-sent events for real-time data streaming.
1707
1968
 
@@ -1764,7 +2025,7 @@ function UserStreamComponent() {
1764
2025
  }
1765
2026
  ```
1766
2027
 
1767
- #### Auto Execute Example
2028
+ ###### Auto Execute Example
1768
2029
 
1769
2030
  ```typescript jsx
1770
2031
  import { useFetcherListStreamQuery } from '@ahoo-wang/fetcher-react';
@@ -1820,7 +2081,7 @@ const MyComponent = () => {
1820
2081
  };
1821
2082
  ```
1822
2083
 
1823
- ### useFetcherSingleQuery Hook
2084
+ ##### useFetcherSingleQuery Hook
1824
2085
 
1825
2086
  The `useFetcherSingleQuery` hook is a specialized React hook for performing single item queries using the Fetcher library. It is designed for fetching a single item with support for filtering and sorting through the SingleQuery type, returning a single result item.
1826
2087
 
@@ -1864,7 +2125,7 @@ function UserProfileComponent({ userId }: { userId: string }) {
1864
2125
  }
1865
2126
  ```
1866
2127
 
1867
- #### Auto Execute Example
2128
+ ###### Auto Execute Example
1868
2129
 
1869
2130
  ```typescript jsx
1870
2131
  import { useFetcherSingleQuery } from '@ahoo-wang/fetcher-react';
@@ -1896,103 +2157,11 @@ const MyComponent = () => {
1896
2157
  };
1897
2158
  ```
1898
2159
 
1899
- ### Stream Query Hooks
1900
-
1901
- #### useListStreamQuery Hook
1902
-
1903
- The `useListStreamQuery` hook manages list stream queries that return a readable stream of server-sent events.
1904
-
1905
- ```typescript jsx
1906
- import { useListStreamQuery } from '@ahoo-wang/fetcher-react';
1907
-
1908
- const MyComponent = () => {
1909
- const { result, loading, error, execute, setCondition } = useListStreamQuery({
1910
- initialQuery: { condition: {}, projection: {}, sort: [], limit: 100 },
1911
- execute: async (listQuery) => {
1912
- // Your stream fetching logic here
1913
- return fetchListStream(listQuery);
1914
- },
1915
- });
1916
-
1917
- useEffect(() => {
1918
- if (result) {
1919
- const reader = result.getReader();
1920
- const readStream = async () => {
1921
- try {
1922
- while (true) {
1923
- const { done, value } = await reader.read();
1924
- if (done) break;
1925
- console.log('Received:', value);
1926
- // Process the stream event
1927
- }
1928
- } catch (error) {
1929
- console.error('Stream error:', error);
1930
- }
1931
- };
1932
- readStream();
1933
- }
1934
- }, [result]);
1935
-
1936
- if (loading) return <div>Loading...</div>;
1937
- if (error) return <div>Error: {error.message}</div>;
1938
-
1939
- return (
1940
- <div>
1941
- <button onClick={execute}>Start Stream</button>
1942
- </div>
1943
- );
1944
- };
1945
- ```
1946
-
1947
- #### Auto Execute Example
1948
-
1949
- ```typescript jsx
1950
- import { useListStreamQuery } from '@ahoo-wang/fetcher-react';
1951
-
1952
- const MyComponent = () => {
1953
- const { result, loading, error, execute, setCondition } = useListStreamQuery({
1954
- initialQuery: { condition: {}, projection: {}, sort: [], limit: 100 },
1955
- execute: async (listQuery) => fetchListStream(listQuery),
1956
- autoExecute: true, // Automatically execute on component mount
1957
- });
1958
-
1959
- useEffect(() => {
1960
- if (result) {
1961
- const reader = result.getReader();
1962
- const readStream = async () => {
1963
- try {
1964
- while (true) {
1965
- const { done, value } = await reader.read();
1966
- if (done) break;
1967
- console.log('Received:', value);
1968
- // Process the stream event
1969
- }
1970
- } catch (error) {
1971
- console.error('Stream error:', error);
1972
- }
1973
- };
1974
- readStream();
1975
- }
1976
- }, [result]);
1977
-
1978
- // The query will execute automatically when the component mounts
1979
-
1980
- if (loading) return <div>Loading...</div>;
1981
- if (error) return <div>Error: {error.message}</div>;
1982
-
1983
- return (
1984
- <div>
1985
- {/* Stream is already started automatically */}
1986
- </div>
1987
- );
1988
- };
1989
- ```
1990
-
1991
2160
  ## Best Practices
1992
2161
 
1993
2162
  ### Performance Optimization
1994
2163
 
1995
- - Use `autoExecute: true` sparingly to avoid unnecessary requests on mount
2164
+ - Use `autoExecute: false` when you need to control when queries execute
1996
2165
  - Leverage `setQuery` for query updates when `autoExecute` is enabled to trigger automatic re-execution
1997
2166
  - Memoize expensive computations in your `execute` functions
1998
2167
 
@@ -2070,7 +2239,7 @@ import { Component, ErrorInfo, ReactNode } from 'react';
2070
2239
  class FetchErrorBoundary extends Component<
2071
2240
  { children: ReactNode; fallback?: ReactNode },
2072
2241
  { hasError: boolean; error?: Error }
2073
- > {
2242
+ > {
2074
2243
  constructor(props: { children: ReactNode; fallback?: ReactNode }) {
2075
2244
  super(props);
2076
2245
  this.state = { hasError: false };
@@ -2852,6 +3021,96 @@ An object implementing `UseRefsReturn<T>` with:
2852
3021
  - `RefKey = string | number | symbol`
2853
3022
  - `UseRefsReturn<T> extends Iterable<[RefKey, T]>`
2854
3023
 
3024
+ ### useQuery
3025
+
3026
+ ```typescript
3027
+ function useQuery<Q, R, E = FetcherError>(
3028
+ options: UseQueryOptions<Q, R, E>,
3029
+ ): UseQueryReturn<Q, R, E>;
3030
+ ```
3031
+
3032
+ A React hook for managing query-based asynchronous operations with automatic state management and execution control.
3033
+
3034
+ **Type Parameters:**
3035
+
3036
+ - `Q`: The type of the query parameters
3037
+ - `R`: The type of the result value
3038
+ - `E`: The type of the error value (defaults to FetcherError)
3039
+
3040
+ **Parameters:**
3041
+
3042
+ - `options`: Configuration options for the query
3043
+ - `initialQuery`: The initial query parameters
3044
+ - `execute`: Function to execute the query with given parameters and optional attributes
3045
+ - `autoExecute?`: Whether to automatically execute the query on mount and when query changes
3046
+ - All options from `UseExecutePromiseOptions`
3047
+
3048
+ **Returns:**
3049
+
3050
+ An object containing the query state and control functions:
3051
+
3052
+ - `loading`: Boolean indicating if the query is currently executing
3053
+ - `result`: The resolved value of the query
3054
+ - `error`: Any error that occurred during execution
3055
+ - `status`: Current execution status
3056
+ - `execute`: Function to execute the query with current parameters
3057
+ - `reset`: Function to reset the promise state
3058
+ - `abort`: Function to abort the current operation
3059
+ - `getQuery`: Function to retrieve the current query parameters
3060
+ - `setQuery`: Function to update the query parameters
3061
+
3062
+ ### useQueryState
3063
+
3064
+ ```typescript
3065
+ function useQueryState<Q>(
3066
+ options: UseQueryStateOptions<Q>,
3067
+ ): UseQueryStateReturn<Q>;
3068
+ ```
3069
+
3070
+ A React hook for managing query state with automatic execution capabilities.
3071
+
3072
+ **Type Parameters:**
3073
+
3074
+ - `Q`: The type of the query parameters
3075
+
3076
+ **Parameters:**
3077
+
3078
+ - `options`: Configuration options for the hook
3079
+ - `initialQuery`: The initial query parameters to be stored and managed
3080
+ - `autoExecute?`: Whether to automatically execute when the query changes or on component mount
3081
+ - `execute`: Function to execute with the current query parameters
3082
+
3083
+ **Returns:**
3084
+
3085
+ An object containing:
3086
+
3087
+ - `getQuery`: Function to retrieve the current query parameters
3088
+ - `setQuery`: Function to update the query parameters. Triggers execution if autoExecute is true
3089
+
3090
+ ### useMounted
3091
+
3092
+ ```typescript
3093
+ function useMounted(): () => boolean;
3094
+ ```
3095
+
3096
+ A React hook that returns a function to check if the component is still mounted.
3097
+
3098
+ **Returns:**
3099
+
3100
+ A function that returns `true` if the component is still mounted, `false` otherwise.
3101
+
3102
+ ### useForceUpdate
3103
+
3104
+ ```typescript
3105
+ function useForceUpdate(): () => void;
3106
+ ```
3107
+
3108
+ A React hook that returns a function to force a component to re-render.
3109
+
3110
+ **Returns:**
3111
+
3112
+ A function that forces the component to re-render when called.
3113
+
2855
3114
  ### useEventSubscription
2856
3115
 
2857
3116
  ```typescript
@@ -3013,7 +3272,7 @@ A React hook for managing list queries with state management for conditions, pro
3013
3272
  **Parameters:**
3014
3273
 
3015
3274
  - `options`: Configuration options including initialQuery and list function
3016
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3275
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3017
3276
 
3018
3277
  **Returns:**
3019
3278
 
@@ -3038,7 +3297,7 @@ A React hook for managing paged queries with state management for conditions, pr
3038
3297
  **Parameters:**
3039
3298
 
3040
3299
  - `options`: Configuration options including initialQuery and query function
3041
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3300
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3042
3301
 
3043
3302
  **Returns:**
3044
3303
 
@@ -3063,7 +3322,7 @@ A React hook for managing single queries with state management for conditions, p
3063
3322
  **Parameters:**
3064
3323
 
3065
3324
  - `options`: Configuration options including initialQuery and query function
3066
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3325
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3067
3326
 
3068
3327
  **Returns:**
3069
3328
 
@@ -3087,7 +3346,7 @@ A React hook for managing count queries with state management for conditions.
3087
3346
  **Parameters:**
3088
3347
 
3089
3348
  - `options`: Configuration options including initialQuery and execute function
3090
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3349
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3091
3350
 
3092
3351
  **Returns:**
3093
3352
 
@@ -3113,7 +3372,7 @@ A React hook for performing count queries using the Fetcher library. It wraps th
3113
3372
  - `options`: Configuration options for the count query, including the condition, fetcher instance, and other query settings
3114
3373
  - `url`: The URL to fetch the count from
3115
3374
  - `initialQuery`: The initial condition for the count query
3116
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3375
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3117
3376
 
3118
3377
  **Returns:**
3119
3378
 
@@ -3144,7 +3403,7 @@ A React hook for performing paged queries using the Fetcher library. It wraps th
3144
3403
  - `options`: Configuration options for the paged query, including the paged query parameters, fetcher instance, and other query settings
3145
3404
  - `url`: The URL to fetch the paged data from
3146
3405
  - `initialQuery`: The initial paged query configuration
3147
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3406
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3148
3407
 
3149
3408
  **Returns:**
3150
3409
 
@@ -3175,7 +3434,7 @@ A React hook for executing list queries using the fetcher library within the wow
3175
3434
  - `options`: Configuration options for the list query, including the list query parameters, fetcher instance, and other query settings
3176
3435
  - `url`: The URL to fetch the list data from
3177
3436
  - `initialQuery`: The initial list query configuration
3178
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3437
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3179
3438
 
3180
3439
  **Returns:**
3181
3440
 
@@ -3206,7 +3465,7 @@ A React hook for performing list stream queries using the Fetcher library with s
3206
3465
  - `options`: Configuration options for the list stream query, including the list query parameters, fetcher instance, and other query settings
3207
3466
  - `url`: The URL to fetch the stream data from
3208
3467
  - `initialQuery`: The initial list query configuration
3209
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3468
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3210
3469
 
3211
3470
  **Returns:**
3212
3471
 
@@ -3237,7 +3496,7 @@ A React hook for executing single item queries using the fetcher library within
3237
3496
  - `options`: Configuration options for the single query, including the single query parameters, fetcher instance, and other query settings
3238
3497
  - `url`: The URL to fetch the single item from
3239
3498
  - `initialQuery`: The initial single query configuration
3240
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3499
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3241
3500
 
3242
3501
  **Returns:**
3243
3502
 
@@ -3267,7 +3526,7 @@ Returns a readable stream of JSON server-sent events.
3267
3526
  **Parameters:**
3268
3527
 
3269
3528
  - `options`: Configuration options including initialQuery and listStream function
3270
- - `autoExecute`: Whether to automatically execute the query on component mount (defaults to false)
3529
+ - `autoExecute`: Whether to automatically execute the query on component mount (defaults to true)
3271
3530
 
3272
3531
  **Returns:**
3273
3532