UNPKG

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