-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuseApi.ts
92 lines (81 loc) · 2.7 KB
/
useApi.ts
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import {useEffect, useMemo, useState} from "react";
export enum ApiStatus {
initial = 'initial',
loading = 'loading',
success = 'success',
failed = 'failed',
canceled = 'canceled',
}
export interface ApiState {
resetValue(): void,
cancelRequest(): void,
status: ApiStatus,
error: any | null, // Set error type isn't save. Response from failed api request may be have not expected format
isInitial: boolean,
isLoading: boolean,
isCanceled: boolean,
isSuccess: boolean,
isFailed: boolean,
}
type State<TResult> = {
result: TResult,
status: ApiStatus,
error: any | null
};
export type UseApi = <TResponse, TInitialValue, TRequest = void>(
asyncFunc: (arg: TRequest) => Promise<TResponse>,
initialValue: TInitialValue,
) => [TResponse | TInitialValue, (payload: TRequest) => void, ApiState];
const useApi: UseApi = <TResponse, TInitialValue, TRequest>(
asyncFunc: (payload: TRequest) => Promise<TResponse>,
initialResult: TInitialValue,
): [TResponse | TInitialValue, (payload: TRequest) => void, ApiState] => {
const [state, setState] = useState<State<TResponse | TInitialValue>>({
result: initialResult,
status: ApiStatus.initial,
error: null
});
useEffect(() => {
return () => setState({ ...state, status: ApiStatus.canceled, error: null });
}, []);
const request = (payload: TRequest) => {
setState({ ...state, status: ApiStatus.loading, error: null });
return asyncFunc(payload)
.then((result) => {
// Was the validation request canceled at run time?
if (state.status !== ApiStatus.canceled) {
setState({ result, status: ApiStatus.success, error: null });
}
})
.catch((error) => {
// Was the validation request canceled at run time?
if (state.status === ApiStatus.canceled) {
return;
}
setState({ ...state, status: ApiStatus.failed, error });
});
};
const resultState = useMemo((): ApiState => {
return {
cancelRequest: () => setState({
...state,
status: ApiStatus.canceled,
error: null
}),
resetValue: () => setState({
result: initialResult,
status: ApiStatus.initial,
error: null
}),
error: state.error,
status: state.status,
isInitial: state.status === ApiStatus.initial,
isLoading: state.status === ApiStatus.loading,
isFailed: state.status === ApiStatus.failed,
isCanceled: state.status === ApiStatus.canceled,
isSuccess: state.status === ApiStatus.success,
};
}, [state]);
return [state.result, request, resultState];
};
export default useApi;