From 6a7ee474d220e2245607b1510d1d0514e8bd7a89 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Sun, 8 Feb 2026 19:27:48 +0530 Subject: [PATCH] feat(20-01): integrate removeVuState with mixer lifecycle - Destructure removeVuState from useVuContext alongside updateVU3 - Add previousMixerIdsRef to track mixer IDs between renders - Add cleanup useEffect that detects removed mixers - Call removeVuState when mixer is removed from allMixers - Only run cleanup when mixers are ready (isReadyRedux is true) This prevents unbounded growth of vuStates object as tracks join/leave. Co-Authored-By: Claude Opus 4.5 --- jam-ui/src/hooks/useMixerHelper.js | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/jam-ui/src/hooks/useMixerHelper.js b/jam-ui/src/hooks/useMixerHelper.js index 5e2906db7..299388bb6 100644 --- a/jam-ui/src/hooks/useMixerHelper.js +++ b/jam-ui/src/hooks/useMixerHelper.js @@ -66,6 +66,7 @@ const useMixerHelper = () => { const dispatch = useDispatch(); const allMixersRef = useRef({}); const previousMyTracksRef = useRef([]); + const previousMixerIdsRef = useRef(null); // Redux selectors - replace all useState calls const chatMixer = useSelector(selectChatMixer); @@ -108,7 +109,7 @@ const useMixerHelper = () => { const currentSession = useSelector(selectActiveSession); const inSession = useSelector(selectInSession); const { jamClient, isConnected, server } = useJamServerContext(); - const { updateVU3 } = useVuContext(); + const { updateVU3, removeVuState } = useVuContext(); const { getParticipant } = useSessionHelper(); const { trackVolumeObject, setTrackVolumeObject } = useGlobalContext(); const faderHelpers = useFaderHelpers(); @@ -316,6 +317,33 @@ const useMixerHelper = () => { } }, [isReadyRedux]); + // Cleanup VU state when mixers are removed + useEffect(() => { + // Skip if not ready or no previous mixers to compare + if (!isReadyRedux) return; + + // Get current mixer IDs from allMixers + const currentMixerIds = new Set(Object.keys(allMixers)); + + // Track previous mixer IDs using a ref + if (!previousMixerIdsRef.current) { + previousMixerIdsRef.current = currentMixerIds; + return; + } + + // Find removed mixers (in previous but not in current) + for (const mixerId of previousMixerIdsRef.current) { + if (!currentMixerIds.has(mixerId)) { + // Mixer was removed - clean up its VU state + removeVuState(mixerId); + console.debug('[useMixerHelper] Cleaned up VU state for removed mixer:', mixerId); + } + } + + // Update previous for next comparison + previousMixerIdsRef.current = currentMixerIds; + }, [allMixers, isReadyRedux, removeVuState]); + const getMixerByTrackId = useCallback((trackId, mode) => { const mixerPair = mixersByTrackId[trackId];