-
Notifications
You must be signed in to change notification settings - Fork 0
/
useLoader.ts
100 lines (90 loc) · 2.12 KB
/
useLoader.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
93
94
95
96
97
98
99
100
import { useMemo, useEffect, useState, useCallback } from "react";
import { run, type Callable } from "effection";
import { CreateLoaderOptions, createLoader } from "../operations/createLoader";
import { setUpdateContext, update } from "../operations/UpdateContext";
export type LoaderState<T> =
| {
type: "initial";
}
| {
type: "started";
}
| {
type: "loading";
count: number;
}
| {
type: "loading-slowly";
}
| {
type: "success";
value: T;
}
| {
type: "failed-attempt";
attempt: number;
error: Error;
}
| {
type: "retrying";
error: Error;
}
| {
type: "failed";
error: Error;
};
export type LoaderFn<T> = (params: {
attempt: number;
signal: AbortSignal;
}) => Callable<T>;
export type UseLoaderOptions<T> = Partial<Omit<CreateLoaderOptions<T>, "load">>;
export function useLoader<T>(
load: LoaderFn<T>,
options: UseLoaderOptions<T> = {}
) {
const {
retryAttempts = 3,
showSpinnerAfterInterval = 1000,
loadingInterval = 3000,
loadingSlowlyInterval = 4000,
failedAttemptErrorInterval = 1000,
retryingMessageInterval = 1000,
} = options;
const [state, setState] = useState<LoaderState<unknown>>({ type: "initial" });
const [key, setKey] = useState<number>(0);
const restart = useCallback(() => {
setKey(key + 1);
}, [key, setKey]);
const loader = useMemo(
() =>
createLoader({
retryAttempts,
load,
showSpinnerAfterInterval,
loadingInterval,
loadingSlowlyInterval,
failedAttemptErrorInterval,
retryingMessageInterval,
}),
[
failedAttemptErrorInterval,
load,
loadingInterval,
loadingSlowlyInterval,
retryAttempts,
retryingMessageInterval,
showSpinnerAfterInterval,
]
);
useEffect(() => {
const task = run(function* () {
yield* setUpdateContext(setState);
yield* update({ type: "initial" })
yield* loader();
});
return () => {
run(() => task.halt());
};
}, [loader, key]);
return [state, { restart }] as const;
}