57 lines
1.2 KiB
TypeScript
57 lines
1.2 KiB
TypeScript
"use client";
|
|||
|
|
|
||
|
|
import { useEffect, useRef } from "react";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Run `tick` on an interval, but pause while the document is hidden
|
||
|
|
* (background Safari tab / phone locked). Resumes with an immediate tick
|
||
|
|
* when the page becomes visible again.
|
||
|
|
*/
|
||
|
|
export function useVisibilityAwarePoll(
|
||
|
|
tick: () => void | Promise<void>,
|
||
|
|
intervalMs: number,
|
||
|
|
enabled = true,
|
||
|
|
): void {
|
||
|
|
const tickRef = useRef(tick);
|
||
|
|
tickRef.current = tick;
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!enabled || intervalMs <= 0) return;
|
||
|
|
|
||
|
|
let id: ReturnType<typeof setInterval> | null = null;
|
||
|
|
|
||
|
|
const run = () => {
|
||
|
|
void tickRef.current();
|
||
|
|
};
|
||
|
|
|
||
|
|
const start = () => {
|
||
|
|
if (id != null) return;
|
||
|
|
id = setInterval(run, intervalMs);
|
||
|
|
};
|
||
|
|
|
||
|
|
const stop = () => {
|
||
|
|
if (id != null) {
|
||
|
|
clearInterval(id);
|
||
|
|
id = null;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const onVisibility = () => {
|
||
|
|
if (document.hidden) {
|
||
|
|
stop();
|
||
|
|
} else {
|
||
|
|
run();
|
||
|
|
start();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
if (!document.hidden) start();
|
||
|
|
|
||
|
|
document.addEventListener("visibilitychange", onVisibility);
|
||
|
|
return () => {
|
||
|
|
stop();
|
||
|
|
document.removeEventListener("visibilitychange", onVisibility);
|
||
|
|
};
|
||
|
|
}, [intervalMs, enabled]);
|
||
|
|
}
|