-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathuseAsyncFunction.ts
More file actions
52 lines (47 loc) · 1.31 KB
/
useAsyncFunction.ts
File metadata and controls
52 lines (47 loc) · 1.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { useState, useCallback } from 'react';
import { useIsMounted } from '@neinteractiveliterature/litform';
export type UseAsyncFunctionOptions = {
suppressError?: boolean;
};
export type WrappedAsyncFunction<T, A extends unknown[]> = (...args: A) => Promise<T | null>;
export type UseAsyncFunctionReturn<T, A extends unknown[]> = [
WrappedAsyncFunction<T, A>,
Error | null,
boolean,
() => void,
];
export default function useAsyncFunction<T, A extends unknown[]>(
func: (...args: A) => Promise<T>,
{ suppressError }: UseAsyncFunctionOptions = {},
): UseAsyncFunctionReturn<T, A> {
const [error, setError] = useState<Error | null>(null);
const [inProgress, setInProgress] = useState<boolean>(false);
const isMounted = useIsMounted();
return [
useCallback(
async (...args: A) => {
setError(null);
setInProgress(true);
try {
return await func(...args);
} catch (e) {
if (isMounted.current) {
setError(e as Error);
}
if (!suppressError) {
throw e;
}
return null;
} finally {
if (isMounted.current) {
setInProgress(false);
}
}
},
[func, suppressError, isMounted],
),
error,
inProgress,
() => setError(null),
];
}