mirror of
https://github.com/idanoo/GoScrobble.git
synced 2024-11-23 00:45:16 +00:00
74 lines
2.1 KiB
JavaScript
74 lines
2.1 KiB
JavaScript
import { useMemo, useRef } from 'react';
|
|
import useMounted from './useMounted';
|
|
import useWillUnmount from './useWillUnmount';
|
|
/*
|
|
* Browsers including Internet Explorer, Chrome, Safari, and Firefox store the
|
|
* delay as a 32-bit signed integer internally. This causes an integer overflow
|
|
* when using delays larger than 2,147,483,647 ms (about 24.8 days),
|
|
* resulting in the timeout being executed immediately.
|
|
*
|
|
* via: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
|
|
*/
|
|
|
|
var MAX_DELAY_MS = Math.pow(2, 31) - 1;
|
|
|
|
function setChainedTimeout(handleRef, fn, timeoutAtMs) {
|
|
var delayMs = timeoutAtMs - Date.now();
|
|
handleRef.current = delayMs <= MAX_DELAY_MS ? setTimeout(fn, delayMs) : setTimeout(function () {
|
|
return setChainedTimeout(handleRef, fn, timeoutAtMs);
|
|
}, MAX_DELAY_MS);
|
|
}
|
|
/**
|
|
* Returns a controller object for setting a timeout that is properly cleaned up
|
|
* once the component unmounts. New timeouts cancel and replace existing ones.
|
|
*
|
|
*
|
|
*
|
|
* ```tsx
|
|
* const { set, clear } = useTimeout();
|
|
* const [hello, showHello] = useState(false);
|
|
* //Display hello after 5 seconds
|
|
* set(() => showHello(true), 5000);
|
|
* return (
|
|
* <div className="App">
|
|
* {hello ? <h3>Hello</h3> : null}
|
|
* </div>
|
|
* );
|
|
* ```
|
|
*/
|
|
|
|
|
|
export default function useTimeout() {
|
|
var isMounted = useMounted(); // types are confused between node and web here IDK
|
|
|
|
var handleRef = useRef();
|
|
useWillUnmount(function () {
|
|
return clearTimeout(handleRef.current);
|
|
});
|
|
return useMemo(function () {
|
|
var clear = function clear() {
|
|
return clearTimeout(handleRef.current);
|
|
};
|
|
|
|
function set(fn, delayMs) {
|
|
if (delayMs === void 0) {
|
|
delayMs = 0;
|
|
}
|
|
|
|
if (!isMounted()) return;
|
|
clear();
|
|
|
|
if (delayMs <= MAX_DELAY_MS) {
|
|
// For simplicity, if the timeout is short, just set a normal timeout.
|
|
handleRef.current = setTimeout(fn, delayMs);
|
|
} else {
|
|
setChainedTimeout(handleRef, fn, Date.now() + delayMs);
|
|
}
|
|
}
|
|
|
|
return {
|
|
set: set,
|
|
clear: clear
|
|
};
|
|
}, []);
|
|
} |