70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
import { useEffect, useRef } from "react";
|
|
|
|
type UseIntervalOptions = {
|
|
/** If passed, will refresh every interval MS */
|
|
interval?: number;
|
|
onLoad?: boolean;
|
|
onFocus?: boolean;
|
|
disabled?: boolean;
|
|
/** Skip interval ticks while the document tab is hidden */
|
|
pauseWhenHidden?: boolean;
|
|
callback: () => void;
|
|
};
|
|
|
|
export function useInterval({
|
|
interval,
|
|
onLoad = true,
|
|
onFocus = true,
|
|
disabled = false,
|
|
pauseWhenHidden = false,
|
|
callback,
|
|
}: UseIntervalOptions) {
|
|
// Always keep the latest callback in a ref so the effects below
|
|
// never close over a stale version.
|
|
const latestCallback = useRef(callback);
|
|
useEffect(() => {
|
|
latestCallback.current = callback;
|
|
}, [callback]);
|
|
|
|
// On interval
|
|
useEffect(() => {
|
|
if (!interval || interval <= 0 || disabled) return;
|
|
|
|
const intervalId = setInterval(() => {
|
|
if (pauseWhenHidden && document.visibilityState !== "visible") {
|
|
return;
|
|
}
|
|
latestCallback.current();
|
|
}, interval);
|
|
|
|
return () => clearInterval(intervalId);
|
|
}, [interval, disabled, pauseWhenHidden]);
|
|
|
|
// On focus
|
|
useEffect(() => {
|
|
if (!onFocus || disabled) return;
|
|
|
|
const handleFocus = () => {
|
|
if (document.visibilityState === "visible") {
|
|
latestCallback.current();
|
|
}
|
|
};
|
|
|
|
// Revalidate when the page becomes visible
|
|
document.addEventListener("visibilitychange", handleFocus);
|
|
// Revalidate when the window gains focus
|
|
window.addEventListener("focus", handleFocus);
|
|
|
|
return () => {
|
|
document.removeEventListener("visibilitychange", handleFocus);
|
|
window.removeEventListener("focus", handleFocus);
|
|
};
|
|
}, [onFocus, disabled]);
|
|
|
|
// On load
|
|
useEffect(() => {
|
|
if (disabled || !onLoad) return;
|
|
latestCallback.current();
|
|
}, [disabled, onLoad]);
|
|
}
|