Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Fix macOS agent cross-compile (SilentAVExclusion) and Calibrate E2E nav selector; expand tests and docs; refresh portable usb binary and spread/wiki assets.
37 lines
1.3 KiB
TypeScript
37 lines
1.3 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
|
|
/** True when the document tab is visible (Page Visibility API). */
|
|
export function usePageVisible(): boolean {
|
|
const [visible, setVisible] = useState(
|
|
() => typeof document === 'undefined' || document.visibilityState === 'visible',
|
|
);
|
|
|
|
useEffect(() => {
|
|
const onVis = () => setVisible(document.visibilityState === 'visible');
|
|
document.addEventListener('visibilitychange', onVis);
|
|
return () => document.removeEventListener('visibilitychange', onVis);
|
|
}, []);
|
|
|
|
return visible;
|
|
}
|
|
|
|
/**
|
|
* Run `fn` on an interval; pauses while the tab is hidden.
|
|
*
|
|
* `fn` is stored in a ref so callers do NOT need to wrap it in `useCallback`.
|
|
* The effect only re-runs when `ms`, `enabled`, or tab-visibility changes —
|
|
* an unstable `fn` reference will NOT trigger extra immediate calls.
|
|
*/
|
|
export function useVisibleInterval(fn: () => void, ms: number, enabled = true): void {
|
|
const visible = usePageVisible();
|
|
const fnRef = useRef(fn);
|
|
// Keep the ref in sync with the latest fn without scheduling a new interval.
|
|
fnRef.current = fn;
|
|
|
|
useEffect(() => {
|
|
if (!enabled || !visible) return;
|
|
const id = window.setInterval(() => fnRef.current(), ms);
|
|
return () => window.clearInterval(id);
|
|
}, [ms, enabled, visible]);
|
|
}
|