From 879abba10bbaa6e52da56e25d2510df3e64d86c5 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Jan 2026 06:48:21 +0000 Subject: [PATCH] fix: Memory leak in battery API event listeners The battery level and charging event listeners were added but never cleaned up when the component unmounts. This caused memory leaks as anonymous functions couldn't be removed. Fix: - Store handler references in variables - Properly cleanup event listeners in useEffect return function - Prevents memory leaks on component unmount/remount cycles --- client/src/pages/os.tsx | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/client/src/pages/os.tsx b/client/src/pages/os.tsx index 7159675..41ec7c4 100644 --- a/client/src/pages/os.tsx +++ b/client/src/pages/os.tsx @@ -230,17 +230,34 @@ export default function AeThexOS() { const [batteryInfo, setBatteryInfo] = useState<{ level: number; charging: boolean } | null>(null); useEffect(() => { + let battery: any = null; + let levelChangeHandler: (() => void) | null = null; + let chargingChangeHandler: (() => void) | null = null; + if ('getBattery' in navigator) { - (navigator as any).getBattery().then((battery: any) => { + (navigator as any).getBattery().then((bat: any) => { + battery = bat; setBatteryInfo({ level: Math.round(battery.level * 100), charging: battery.charging }); - battery.addEventListener('levelchange', () => { + + levelChangeHandler = () => { setBatteryInfo(prev => prev ? { ...prev, level: Math.round(battery.level * 100) } : null); - }); - battery.addEventListener('chargingchange', () => { + }; + chargingChangeHandler = () => { setBatteryInfo(prev => prev ? { ...prev, charging: battery.charging } : null); - }); + }; + + battery.addEventListener('levelchange', levelChangeHandler); + battery.addEventListener('chargingchange', chargingChangeHandler); }); } + + // Cleanup: remove battery event listeners to prevent memory leak + return () => { + if (battery) { + if (levelChangeHandler) battery.removeEventListener('levelchange', levelChangeHandler); + if (chargingChangeHandler) battery.removeEventListener('chargingchange', chargingChangeHandler); + } + }; }, []); const { data: weatherData, isFetching: weatherFetching } = useQuery({