-
Notifications
You must be signed in to change notification settings - Fork 95
/
index.ts
52 lines (44 loc) · 1.3 KB
/
index.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
import {useCallback, useEffect, useRef} from 'react';
import {useSyncedRef} from '../useSyncedRef/index.js';
type TimeoutID = ReturnType<typeof setTimeout> | null;
const cancelTimeout = (id: TimeoutID) => {
if (id) {
clearTimeout(id);
}
};
/**
* Like `setTimeout` but in the form of a react hook.
*
* @param callback Callback to be called after the timeout. Changing this
* will not reset the timeout.
* @param ms Timeout delay in milliseconds. `undefined` disables the timeout.
* Keep in mind, that changing this parameter will re-set timeout, meaning
* that it will be set as new after the change.
*/
export function useTimeoutEffect(
callback: () => void,
ms?: number,
): [cancel: () => void, reset: () => void] {
const cbRef = useSyncedRef(callback);
const msRef = useSyncedRef(ms);
const timeoutIdRef = useRef<TimeoutID>(null);
const cancel = useCallback(() => {
cancelTimeout(timeoutIdRef.current);
}, []);
const reset = useCallback(() => {
if (msRef.current === undefined) {
return;
}
cancel();
timeoutIdRef.current = setTimeout(() => {
cbRef.current();
}, msRef.current);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
reset();
return cancel;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ms]);
return [cancel, reset];
}