Skip to content

Commit 837266f

Browse files
committed
feat(FR-1530): Implement window focus check for automatic refresh interval
1 parent 3d98753 commit 837266f

File tree

2 files changed

+56
-13
lines changed

2 files changed

+56
-13
lines changed

react/src/components/BAIFetchKeyButton.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface BAIAutoRefetchButtonProps
1616
size?: ButtonProps['size'];
1717
onChange: (fetchKey: string) => void;
1818
hidden?: boolean;
19+
pauseWhenHidden?: boolean;
1920
}
2021
const BAIFetchKeyButton: React.FC<BAIAutoRefetchButtonProps> = ({
2122
value,
@@ -26,6 +27,7 @@ const BAIFetchKeyButton: React.FC<BAIAutoRefetchButtonProps> = ({
2627
size,
2728
hidden,
2829
lastLoadTime: lastLoadTimeProp,
30+
pauseWhenHidden = true,
2931
...buttonProps
3032
}) => {
3133
const { t } = useTranslation();
@@ -65,6 +67,7 @@ const BAIFetchKeyButton: React.FC<BAIAutoRefetchButtonProps> = ({
6567
},
6668
showLastLoadTime ? 5_000 : null,
6769
lastLoadTime.toISOString(),
70+
pauseWhenHidden,
6871
);
6972

7073
// remember when loading is done to display when the last fetch was done
@@ -80,6 +83,7 @@ const BAIFetchKeyButton: React.FC<BAIAutoRefetchButtonProps> = ({
8083
},
8184
// only start auto-updating after the previous loading is false(done).
8285
loading ? null : autoUpdateDelay,
86+
pauseWhenHidden,
8387
);
8488

8589
const tooltipTitle = showLastLoadTime ? loadTimeMessage : undefined;

react/src/hooks/useIntervalValue.tsx

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,57 @@ import { useEffect, useRef, useState } from 'react';
55
*
66
* @param callback The function to be executed at the specified interval.
77
* @param delay The delay (in milliseconds) between each execution of the callback function. If `null`, the interval is cleared(pause).
8+
* @param pauseWhenHidden Whether to pause the interval when the page becomes hidden. Defaults to true.
89
*/
9-
export function useInterval(callback: () => void, delay: number | null) {
10+
export function useInterval(
11+
callback: () => void,
12+
delay: number | null,
13+
pauseWhenHidden: boolean = true,
14+
) {
1015
const savedCallback = useRef<() => any>(null);
16+
const [isPageVisible, setIsPageVisible] = useState(() =>
17+
typeof document !== 'undefined' ? !document.hidden : true,
18+
);
1119

1220
useEffect(() => {
1321
savedCallback.current = callback;
1422
});
1523

24+
// Handle page visibility changes
25+
useEffect(() => {
26+
if (!pauseWhenHidden) return;
27+
28+
const handleVisibilityChange = () => {
29+
const visible = !document.hidden;
30+
setIsPageVisible((prev) => {
31+
if (delay !== null && !prev && visible) {
32+
// Execute callback immediately when page becomes visible again
33+
savedCallback.current?.();
34+
}
35+
return visible;
36+
});
37+
};
38+
39+
document.addEventListener('visibilitychange', handleVisibilityChange);
40+
41+
return () => {
42+
document.removeEventListener('visibilitychange', handleVisibilityChange);
43+
};
44+
}, [pauseWhenHidden, delay]);
45+
1646
useEffect(() => {
1747
function tick() {
1848
savedCallback.current?.();
1949
}
2050

2151
if (delay !== null) {
22-
let id = setInterval(tick, delay);
23-
return () => clearInterval(id);
52+
// Only check visibility if pauseWhenHidden is enabled
53+
if (!pauseWhenHidden || isPageVisible) {
54+
let id = setInterval(tick, delay);
55+
return () => clearInterval(id);
56+
}
2457
}
25-
}, [delay]);
58+
}, [delay, pauseWhenHidden, isPageVisible]);
2659
}
2760

2861
/**
@@ -31,14 +64,16 @@ export function useInterval(callback: () => void, delay: number | null) {
3164
* @param calculator - A function that calculates the value.
3265
* @param delay - The delay in milliseconds between updates.
3366
* @param triggerKey - An optional key that triggers an immediate update when changed.
67+
* @param pauseWhenHidden - Whether to pause the interval when the page becomes hidden. Defaults to true.
3468
* @returns The updated value.
3569
*/
36-
export const useIntervalValue = (
37-
calculator: () => any,
70+
export function useIntervalValue<T>(
71+
calculator: () => T,
3872
delay: number | null,
3973
triggerKey?: string,
40-
) => {
41-
const [result, setResult] = useState(calculator());
74+
pauseWhenHidden: boolean = true,
75+
): T {
76+
const [result, setResult] = useState<T>(calculator);
4277

4378
useEffect(() => {
4479
if (triggerKey) {
@@ -47,10 +82,14 @@ export const useIntervalValue = (
4782
// eslint-disable-next-line react-hooks/exhaustive-deps
4883
}, [triggerKey]);
4984

50-
useInterval(() => {
51-
const newResult = calculator();
52-
if (newResult !== result) setResult(newResult);
53-
}, delay);
85+
useInterval(
86+
() => {
87+
const newResult = calculator();
88+
if (newResult !== result) setResult(newResult);
89+
},
90+
delay,
91+
pauseWhenHidden,
92+
);
5493

5594
return result;
56-
};
95+
}

0 commit comments

Comments
 (0)