UNPKG

2.11 kBJavaScriptView Raw
1import { useMemo, useRef } from 'react';
2import useMounted from './useMounted';
3import useWillUnmount from './useWillUnmount';
4/*
5 * Browsers including Internet Explorer, Chrome, Safari, and Firefox store the
6 * delay as a 32-bit signed integer internally. This causes an integer overflow
7 * when using delays larger than 2,147,483,647 ms (about 24.8 days),
8 * resulting in the timeout being executed immediately.
9 *
10 * via: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
11 */
12
13var MAX_DELAY_MS = Math.pow(2, 31) - 1;
14
15function setChainedTimeout(handleRef, fn, timeoutAtMs) {
16 var delayMs = timeoutAtMs - Date.now();
17 handleRef.current = delayMs <= MAX_DELAY_MS ? setTimeout(fn, delayMs) : setTimeout(function () {
18 return setChainedTimeout(handleRef, fn, timeoutAtMs);
19 }, MAX_DELAY_MS);
20}
21/**
22 * Returns a controller object for setting a timeout that is properly cleaned up
23 * once the component unmounts. New timeouts cancel and replace existing ones.
24 *
25 *
26 *
27 * ```tsx
28 * const { set, clear } = useTimeout();
29 * const [hello, showHello] = useState(false);
30 * //Display hello after 5 seconds
31 * set(() => showHello(true), 5000);
32 * return (
33 * <div className="App">
34 * {hello ? <h3>Hello</h3> : null}
35 * </div>
36 * );
37 * ```
38 */
39
40
41export default function useTimeout() {
42 var isMounted = useMounted(); // types are confused between node and web here IDK
43
44 var handleRef = useRef();
45 useWillUnmount(function () {
46 return clearTimeout(handleRef.current);
47 });
48 return useMemo(function () {
49 var clear = function clear() {
50 return clearTimeout(handleRef.current);
51 };
52
53 function set(fn, delayMs) {
54 if (delayMs === void 0) {
55 delayMs = 0;
56 }
57
58 if (!isMounted()) return;
59 clear();
60
61 if (delayMs <= MAX_DELAY_MS) {
62 // For simplicity, if the timeout is short, just set a normal timeout.
63 handleRef.current = setTimeout(fn, delayMs);
64 } else {
65 setChainedTimeout(handleRef, fn, Date.now() + delayMs);
66 }
67 }
68
69 return {
70 set: set,
71 clear: clear
72 };
73 }, []);
74}
\No newline at end of file