From 8adf2d7847f6df48dc81ee44eb6deed3dda46acc Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Mon, 14 Sep 2026 23:11:21 +0100 Subject: [PATCH] Refactor HostDeviceScanner for Enhanced Scanning Logic and State Management - Introduced refs to manage scanning state and active host ID, improving control over scan initiation and termination. - Updated useEffect to handle scanning conditions more effectively, including debouncing stop scan actions. - Enhanced session management and error handling during network scans, ensuring better user feedback and reliability. - Cleaned up component lifecycle management to prevent memory leaks and ensure proper resource cleanup. --- .../Dashboard/common/HostDeviceScanner.jsx | 74 +++++++++++++------ 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/src/components/Dashboard/common/HostDeviceScanner.jsx b/src/components/Dashboard/common/HostDeviceScanner.jsx index c0d60db7..634b67ed 100644 --- a/src/components/Dashboard/common/HostDeviceScanner.jsx +++ b/src/components/Dashboard/common/HostDeviceScanner.jsx @@ -52,6 +52,9 @@ const HostDeviceScanner = ({ ? crypto.randomUUID() : `scan-${Date.now()}-${Math.random().toString(16).slice(2)}` ) + const startedRef = useRef(false) + const activeHostIdRef = useRef(null) + const pendingStopRef = useRef(null) const [scanning, setScanning] = useState(false) const [progress, setProgress] = useState(0) @@ -80,22 +83,52 @@ const HostDeviceScanner = ({ } useEffect(() => { - if (!hostId || connected !== true || !compatible) { - return + const sessionId = sessionIdRef.current + const canScan = Boolean(hostId) && connected === true && compatible + + const stopScan = (targetHostId) => { + if (!targetHostId || !startedRef.current) { + return + } + sendObjectActionRef.current(targetHostId, 'host', { + type: 'scanNetworkStop', + data: { sessionId } + }) + startedRef.current = false + activeHostIdRef.current = null + } + + if (pendingStopRef.current) { + clearTimeout(pendingStopRef.current) + pendingStopRef.current = null + } + + if (!canScan) { + const hostToStop = activeHostIdRef.current + pendingStopRef.current = setTimeout(() => { + stopScan(hostToStop) + pendingStopRef.current = null + }, 250) + return () => { + if (pendingStopRef.current) { + clearTimeout(pendingStopRef.current) + pendingStopRef.current = null + } + } } let cancelled = false - const sessionId = sessionIdRef.current + console.log('Scan session id:', sessionId) const isSessionEvent = (event) => event?.data?.sessionId === sessionId const startScan = () => { - if (cancelled) return - setProgress(0) setCurrentIP(null) setScanError(null) setScanning(true) + setDevices([]) + setSelectedKey(null) sendObjectActionRef.current( hostId, @@ -113,6 +146,7 @@ const HostDeviceScanner = ({ if (result?.success === false) { setScanning(false) setScanError(result.error || 'Failed to start network scan') + startedRef.current = false } } ) @@ -192,29 +226,27 @@ const HostDeviceScanner = ({ onComplete ) - setDevices([]) - setSelectedKey(null) - startScan() + const alreadyRunning = startedRef.current && activeHostIdRef.current === hostId + if (!alreadyRunning) { + if (startedRef.current && activeHostIdRef.current) { + stopScan(activeHostIdRef.current) + } + startedRef.current = true + activeHostIdRef.current = hostId + startScan() + } return () => { cancelled = true if (unsubFound) unsubFound() if (unsubProgress) unsubProgress() if (unsubComplete) unsubComplete() - sendObjectActionRef.current(hostId, 'host', { - type: 'scanNetworkStop', - data: { sessionId } - }) + pendingStopRef.current = setTimeout(() => { + stopScan(hostId) + pendingStopRef.current = null + }, 250) } - }, [ - hostId, - connected, - compatible, - port, - protocol, - connectionInterface, - objectType - ]) + }, [hostId, connected, compatible]) const applyDevice = useCallback( (device) => {