diff --git a/.planning/phases/31-selector-optimization/31-01-PLAN.md b/.planning/phases/31-selector-optimization/31-01-PLAN.md index c891d3330..0246fd853 100644 --- a/.planning/phases/31-selector-optimization/31-01-PLAN.md +++ b/.planning/phases/31-selector-optimization/31-01-PLAN.md @@ -12,8 +12,8 @@ autonomous: true must_haves: truths: - "Single mixer field change triggers 1-3 selector runs instead of 18+" - - "useMixerHelper uses 3-5 composed selectors with shallowEqual" - - "Derived data is memoized via createSelector" + - "useMixerHelper uses 6 composed selectors with shallowEqual" + - "Composed selectors use createSelector to memoize grouped state objects (grouping IS derived data - creates new object from multiple inputs)" artifacts: - path: "jam-ui/src/store/features/mixersSlice.js" provides: "Composed memoized selectors for mixer state" @@ -172,7 +172,7 @@ mixersSlice.js exports 6 composed selectors using createSelector: Task 2: Refactor useMixerHelper to use composed selectors with shallowEqual jam-ui/src/hooks/useMixerHelper.js -Replace 18+ individual useSelector calls with 6 composed selector calls using shallowEqual: +Replace 21 individual useSelector calls (lines 72-92) with 6 composed selector calls using shallowEqual: 1. Update imports at top of file: @@ -209,19 +209,36 @@ import { } from '../store/features/mixersSlice'; ``` -2. Replace the 18+ individual useSelector calls (lines 72-92) with composed selector calls: +2. Replace the 21 individual useSelector calls (lines 72-92) with composed selector calls: -OLD (remove this block): +OLD (remove these 21 lines - lines 72-92): ```javascript const chatMixer = useSelector(selectChatMixer); const broadcastMixer = useSelector(selectBroadcastMixer); const recordingMixer = useSelector(selectRecordingMixer); -// ... 15+ more individual selectors +const recordingTrackMixers = useSelector(selectRecordingTrackMixers); +const backingTrackMixers = useSelector(selectBackingTrackMixers); +const jamTrackMixers = useSelector(selectJamTrackMixers); +const metronomeTrackMixers = useSelector(selectMetronomeTrackMixers); +const adhocTrackMixers = useSelector(selectAdhocTrackMixers); +const masterMixers = useSelector(selectMasterMixers); +const personalMixers = useSelector(selectPersonalMixers); +const allMixers = useSelector(selectAllMixers); +const mixersByResourceId = useSelector(selectMixersByResourceId); +const mixersByTrackId = useSelector(selectMixersByTrackId); +const metronome = useSelector(selectMetronome); +const metronomeSettings = useSelector(selectMetronomeSettings); +const mediaSummary = useSelector(selectMediaSummary); +const noAudioUsers = useSelector(selectNoAudioUsers); +const clientsWithAudioOverride = useSelector(selectClientsWithAudioOverride); +const simulatedMusicCategoryMixers = useSelector(selectSimulatedMusicCategoryMixers); +const simulatedChatCategoryMixers = useSelector(selectSimulatedChatCategoryMixers); +const isReadyRedux = useSelector(selectMixersReady); ``` NEW (replace with): ```javascript -// Composed selectors with shallowEqual - reduces 18+ subscriptions to 6 +// Composed selectors with shallowEqual - reduces 21 subscriptions to 6 const coreMixers = useSelector(selectCoreMixerState, shallowEqual); const trackMixers = useSelector(selectTrackMixerState, shallowEqual); const lookupTables = useSelector(selectMixerLookupTables, shallowEqual); @@ -240,9 +257,9 @@ const { metronome, metronomeSettings, mediaSummary, noAudioUsers, const { simulatedMusicCategoryMixers, simulatedChatCategoryMixers } = simulatedMixers; ``` -This preserves all existing variable names used throughout the hook while reducing selector subscriptions from 18+ to 6. +This preserves all existing variable names used throughout the hook while reducing selector subscriptions from 21 to 6. -IMPORTANT: Keep all other code in useMixerHelper.js unchanged - only modify imports and the selector calls section. +IMPORTANT: Keep all other code in useMixerHelper.js unchanged - only modify imports and the selector calls section. The remaining useSelector calls (lines 95-97 for tracks, 100-101 for mix mode, 109-110 for session) stay as-is. Run syntax check: @@ -250,10 +267,10 @@ Run syntax check: cd jam-ui && node -c src/hooks/useMixerHelper.js ``` -Verify shallowEqual usage: +Verify shallowEqual usage (should appear 7 times: 1 import + 6 useSelector calls): ```bash grep -c "shallowEqual" jam-ui/src/hooks/useMixerHelper.js -# Should return 6 or more (imports + 6 useSelector calls) +# Expected: 7 ``` Verify composed selector imports: @@ -263,22 +280,24 @@ grep "selectTrackMixerState" jam-ui/src/hooks/useMixerHelper.js grep "selectMixerLookupTables" jam-ui/src/hooks/useMixerHelper.js ``` -Count useSelector calls (should be significantly reduced): +Verify old individual selectors removed (lines 72-92 pattern should NOT exist): ```bash -grep -c "useSelector" jam-ui/src/hooks/useMixerHelper.js -# Should be around 9-12 (6 composed + a few remaining individual like selectMixMode) +grep -E "useSelector\(select(ChatMixer|BroadcastMixer|RecordingMixer|RecordingTrackMixers|BackingTrackMixers|JamTrackMixers|MetronomeTrackMixers|AdhocTrackMixers|MasterMixers|PersonalMixers|AllMixers|MixersByResourceId|MixersByTrackId|Metronome[^S]|MetronomeSettings|MediaSummary|NoAudioUsers|ClientsWithAudioOverride|SimulatedMusicCategoryMixers|SimulatedChatCategoryMixers|MixersReady)\)" jam-ui/src/hooks/useMixerHelper.js +# Expected: no matches (empty output) +``` + +Count total useSelector calls (should be exactly 13): +```bash +grep -c "= useSelector(" jam-ui/src/hooks/useMixerHelper.js +# Expected: 13 (6 composed + 3 track selectors + 2 mix mode + 2 session selectors) ``` -useMixerHelper.js uses 6 composed selectors with shallowEqual instead of 18+ individual selectors: -- coreMixers via selectCoreMixerState -- trackMixers via selectTrackMixerState -- lookupTables via selectMixerLookupTables -- masterPersonal via selectMasterPersonalMixers -- metadata via selectMixerMetadata -- simulatedMixers via selectSimulatedCategoryMixers - -All existing variable names preserved via destructuring for backward compatibility. +useMixerHelper.js refactored: +- 21 individual selectors (lines 72-92) removed +- 6 composed selectors with shallowEqual added +- Total useSelector calls reduced from 28 to 13 +- All existing variable names preserved via destructuring for backward compatibility @@ -299,8 +318,8 @@ cd jam-ui && npm run build 2>&1 | head -50 3. **Selector count verification:** - mixersSlice.js should export 6 new composed selectors -- useMixerHelper.js should have 6 useSelector calls with shallowEqual -- Total useSelector calls in useMixerHelper reduced from 18+ to ~10-12 +- useMixerHelper.js should have exactly 13 useSelector calls (6 composed + 7 other) +- Old individual selector pattern (lines 72-92) should be completely removed 4. **Pattern verification:** ```bash @@ -313,6 +332,8 @@ grep -E "createSelector|shallowEqual" jam-ui/src/store/features/mixersSlice.js j - [ ] mixersSlice.js exports 6 composed selectors (selectCoreMixerState, selectTrackMixerState, selectMixerLookupTables, selectMasterPersonalMixers, selectMixerMetadata, selectSimulatedCategoryMixers) - [ ] useMixerHelper.js imports shallowEqual from react-redux - [ ] useMixerHelper.js uses 6 composed selectors with shallowEqual comparison +- [ ] Old individual selectors (lines 72-92) completely removed +- [ ] Total useSelector calls in useMixerHelper.js equals exactly 13 - [ ] All existing variable names preserved via destructuring - [ ] Syntax validation passes for both files - [ ] Build completes without errors