@cripty2001/utils 0.0.143 → 0.0.144

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.
@@ -52,18 +52,61 @@ export declare function useDebounced<T>(value: T): T;
52
52
  */
53
53
  export declare function useSynced<T extends any>(def: T, value: T | undefined, setValue: ((value: T) => void) | undefined): [T, React.Dispatch<React.SetStateAction<T>>];
54
54
  /**
55
+ * Wraps an async function into a reactable data structure that tracks loading state, progress, and results.
55
56
  *
56
- * Wraps an async function into a reactable data.
57
+ * **Error Handling:** This function does NOT throw errors. Instead, errors are stored in the returned dispatcher's state.
58
+ * Check the dispatcher's `data` property to access the error state. The dispatcher's promise resolves successfully
59
+ * even when errors occur - errors are captured and stored in the reactive state for UI consumption.
57
60
  *
58
- * @param f The async function to call. It should return a promise that resolves to the data. It is not reactive
61
+ * @param f The async function to call. It should return a promise that resolves to the data. It is not reactive.
59
62
  * @param data The data to give to f. It must be stable, as anything in the dependency array of the useEffect and similars in the react ecosystem. If null, this function will act like an useEffect with an empty dependency array.
60
- * @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed
61
- * @returns The dispatcher
63
+ * @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed.
64
+ * @returns A Dispatcher object containing:
65
+ * - `data`: A Whispr<DispatcherStatePayload<O>> that contains the loading state, progress, and either the result data or error
66
+ * - `filtered`: A Whispr<O | null> that contains the result data when successful, or null when loading or on error
62
67
  *
63
68
  * @type I Input for the async function.
64
- * @type O Output for the async function
69
+ * @type O Output for the async function.
70
+ *
71
+ * @example
72
+ * const dispatcher = useAsync(async (userId) => {
73
+ * const response = await fetch(`/api/users/${userId}`);
74
+ * return response.json();
75
+ * }, userId);
76
+ *
77
+ * const state = useWhisprValue(dispatcher.data);
78
+ * // state can be: { loading: true, progress: 0 } | { loading: false, ok: true, data: T } | { loading: false, ok: false, error: Error }
79
+ *
80
+ * if (!state.loading && !state.ok) {
81
+ * console.error('Error:', state.error);
82
+ * }
65
83
  */
66
84
  export declare function useAsync<I, O>(f: (input: I, setProgress: (p: number) => void, signal: AbortSignal) => Promise<O>, data: I, debouce?: number): Dispatcher<I, O>;
85
+ /**
86
+ * Async version of useEffect with debouncing. Executes an async function as a side effect when data changes.
87
+ *
88
+ * **Error Handling:** This function THROWS errors. Unlike `useAsync`, errors are not stored in state but are thrown
89
+ * as promise rejections. Use this when you want errors to propagate (e.g., to error boundaries or try/catch blocks).
90
+ *
91
+ * @param f The async function to execute. It should return a promise. It is not reactive.
92
+ * @param data The data that triggers the effect. It must be stable, as anything in the dependency array of useEffect.
93
+ * If null, this function will act like useEffect with an empty dependency array.
94
+ * @param debounce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not
95
+ * passed since the last data change. If another change happens during the wait, the first function call is aborted.
96
+ *
97
+ * @remarks This function returns void - it is purely for side effects, similar to useEffect.
98
+ * @remarks Errors thrown by the async function will cause the promise to reject. If you need to handle errors
99
+ * in the UI without throwing, use `useAsync` instead.
100
+ *
101
+ * @example
102
+ * useAsyncEffect(async (userId, setProgress, signal) => {
103
+ * const response = await fetch(`/api/users/${userId}`, { signal });
104
+ * if (!response.ok) throw new Error('Failed to fetch');
105
+ * const data = await response.json();
106
+ * // Do something with data
107
+ * }, userId, 300);
108
+ */
109
+ export declare function useAsyncEffect<I>(f: (input: I, setProgress: (p: number) => void, signal: AbortSignal) => Promise<void>, data: I, debounce?: number): void;
67
110
  /**
68
111
  * Format a timestamp into a relative time string (e.g. "5 minutes ago", "in 2 hours"), using the browser locale.
69
112
  * The refreshed time is reactive.
@@ -7,6 +7,7 @@ exports.useCurrentTimestamp = useCurrentTimestamp;
7
7
  exports.useDebounced = useDebounced;
8
8
  exports.useSynced = useSynced;
9
9
  exports.useAsync = useAsync;
10
+ exports.useAsyncEffect = useAsyncEffect;
10
11
  exports.useRelTime = useRelTime;
11
12
  exports.useSearcher = useSearcher;
12
13
  exports.useSafeRef = useSafeRef;
@@ -136,16 +137,34 @@ function useSynced(def, value, setValue) {
136
137
  return [v, syncedSetter];
137
138
  }
138
139
  /**
140
+ * Wraps an async function into a reactable data structure that tracks loading state, progress, and results.
139
141
  *
140
- * Wraps an async function into a reactable data.
142
+ * **Error Handling:** This function does NOT throw errors. Instead, errors are stored in the returned dispatcher's state.
143
+ * Check the dispatcher's `data` property to access the error state. The dispatcher's promise resolves successfully
144
+ * even when errors occur - errors are captured and stored in the reactive state for UI consumption.
141
145
  *
142
- * @param f The async function to call. It should return a promise that resolves to the data. It is not reactive
146
+ * @param f The async function to call. It should return a promise that resolves to the data. It is not reactive.
143
147
  * @param data The data to give to f. It must be stable, as anything in the dependency array of the useEffect and similars in the react ecosystem. If null, this function will act like an useEffect with an empty dependency array.
144
- * @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed
145
- * @returns The dispatcher
148
+ * @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed.
149
+ * @returns A Dispatcher object containing:
150
+ * - `data`: A Whispr<DispatcherStatePayload<O>> that contains the loading state, progress, and either the result data or error
151
+ * - `filtered`: A Whispr<O | null> that contains the result data when successful, or null when loading or on error
146
152
  *
147
153
  * @type I Input for the async function.
148
- * @type O Output for the async function
154
+ * @type O Output for the async function.
155
+ *
156
+ * @example
157
+ * const dispatcher = useAsync(async (userId) => {
158
+ * const response = await fetch(`/api/users/${userId}`);
159
+ * return response.json();
160
+ * }, userId);
161
+ *
162
+ * const state = useWhisprValue(dispatcher.data);
163
+ * // state can be: { loading: true, progress: 0 } | { loading: false, ok: true, data: T } | { loading: false, ok: false, error: Error }
164
+ *
165
+ * if (!state.loading && !state.ok) {
166
+ * console.error('Error:', state.error);
167
+ * }
149
168
  */
150
169
  function useAsync(f, data, debouce = 200) {
151
170
  // Initing reactive input
@@ -160,6 +179,38 @@ function useAsync(f, data, debouce = 200) {
160
179
  // Returning dispatcher
161
180
  return dispatcher;
162
181
  }
182
+ /**
183
+ * Async version of useEffect with debouncing. Executes an async function as a side effect when data changes.
184
+ *
185
+ * **Error Handling:** This function THROWS errors. Unlike `useAsync`, errors are not stored in state but are thrown
186
+ * as promise rejections. Use this when you want errors to propagate (e.g., to error boundaries or try/catch blocks).
187
+ *
188
+ * @param f The async function to execute. It should return a promise. It is not reactive.
189
+ * @param data The data that triggers the effect. It must be stable, as anything in the dependency array of useEffect.
190
+ * If null, this function will act like useEffect with an empty dependency array.
191
+ * @param debounce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not
192
+ * passed since the last data change. If another change happens during the wait, the first function call is aborted.
193
+ *
194
+ * @remarks This function returns void - it is purely for side effects, similar to useEffect.
195
+ * @remarks Errors thrown by the async function will cause the promise to reject. If you need to handle errors
196
+ * in the UI without throwing, use `useAsync` instead.
197
+ *
198
+ * @example
199
+ * useAsyncEffect(async (userId, setProgress, signal) => {
200
+ * const response = await fetch(`/api/users/${userId}`, { signal });
201
+ * if (!response.ok) throw new Error('Failed to fetch');
202
+ * const data = await response.json();
203
+ * // Do something with data
204
+ * }, userId, 300);
205
+ */
206
+ function useAsyncEffect(f, data, debounce = 200) {
207
+ const dispatcher = useAsync(f, data, debounce);
208
+ useOnWhispr(dispatcher.data, (data) => {
209
+ if (!data.loading && !data.ok) {
210
+ throw data.error;
211
+ }
212
+ });
213
+ }
163
214
  /**
164
215
  * Format a timestamp into a relative time string (e.g. "5 minutes ago", "in 2 hours"), using the browser locale.
165
216
  * The refreshed time is reactive.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cripty2001/utils",
3
- "version": "0.0.143",
3
+ "version": "0.0.144",
4
4
  "description": "Internal Set of utils. If you need them use them, otherwise go to the next package ;)",
5
5
  "homepage": "https://github.com/cripty2001/utils#readme",
6
6
  "bugs": {