9.2 KiB
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 29-context-optimization | 01 | execute | 1 |
|
true |
|
Purpose: MixersContext creates a new value object on every render (line 10), causing all consumers to re-render even when underlying data hasn't changed. VuContext and GlobalContext have the same issue. This phase applies useMemo to provider values and React.memo to consumer components, so volume slider changes don't re-render VU meters and vice versa.
Output: Memoized context providers (MixersContext, VuContext, GlobalContext) and memo-wrapped consumer components (SessionTrackGain, JKSessionMyTrack, etc.) with verified stable function references.
<execution_context> @/Users/nuwan/.claude/get-shit-done/workflows/execute-plan.md @/Users/nuwan/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/29-context-optimization/29-RESEARCH.md Task 1: Memoize MixersContext provider value jam-ui/src/context/MixersContext.js Memoize the MixersContext.Provider value to prevent new object creation on every render.- Import
useMemofrom 'react' - Wrap the
mixerHelpervalue withuseMemo:const value = useMemo(() => mixerHelper, [mixerHelper]); - Pass
valuetoMixersContext.Providerinstead ofmixerHelperdirectly
The useMixerHelper hook already returns stable references (verified: all functions use useCallback, myTracks uses useMemo). The memoization ensures the context value object itself doesn't recreate unless mixerHelper changes.
Do NOT change useMixerHelper.js - the returned object from useMixerHelper already has stable function references via useCallback (faderChanged, findMixerForTrack, updateMixerData, etc.) and memoized values (myTracks via useMemo).
- Run
cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build- should compile without errors - Check MixersContext.js contains:
import { useMemo }anduseMemo(() => mixerHelper
- MixersContext.Provider value is wrapped with useMemo
- Build passes without errors
VuContext.js:
- Import
useMemofrom 'react' - Memoize the combined value object:
Note: vuStore is a stable module-level reference, doesn't need to be a dependencyconst value = useMemo(() => ({ ...vuHelpers, vuStore, }), [vuHelpers]);
GlobalContext.js:
-
Import
useMemofrom 'react' -
Memoize the provider value using all state/callback dependencies:
const value = useMemo(() => ({ trackVolumeObject, setTrackVolumeObject, globalObject, setGlobalObject, metronomeState, updateMetronomeState, openMetronome, closeMetronome, resetMetronome, }), [ trackVolumeObject, globalObject, metronomeState, updateMetronomeState, openMetronome, closeMetronome, resetMetronome ]);Note: useState setters (setTrackVolumeObject, setGlobalObject) are stable and don't need to be dependencies
-
Pass memoized
valueto provider instead of inline object -
Run
cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build- should compile without errors -
Check VuContext.js contains:
useMemo(() => ({ -
Check GlobalContext.js contains:
useMemo(() => ({
- VuContext.Provider value is wrapped with useMemo
- GlobalContext.Provider value is wrapped with useMemo
- Build passes without errors
Pattern for each file:
- Import
memofrom 'react' (add to existing import) - Wrap the component function definition with memo:
const SessionTrackGain = memo(function SessionTrackGain({ mixers, gainType, ... }) { // existing implementation }); - Add displayName for debugging (optional but helpful):
SessionTrackGain.displayName = 'SessionTrackGain';
Files to update:
SessionTrackGain.js- volume slider, consumes MixersContextJKSessionMyTrack.js- local track display, consumes MixersContextJKSessionVolumeModal.js- volume popup, consumes MixersContextJKSessionPanModal.js- pan control popup, consumes MixersContextJKSessionBackingTrack.js- backing track display, consumes MixersContextJKSessionMetronome.js- metronome controls, consumes MixersContext
Do NOT wrap JKSessionScreen.js (the top-level container) - only wrap the specific consumer components that are frequently re-rendered.
For each component:
- Check if already wrapped with memo - skip if so
- Convert
const ComponentName = (props) => {toconst ComponentName = memo(function ComponentName(props) { - Ensure PropTypes remain attached:
ComponentName.propTypes = {...} - Run
cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build- should compile without errors - Grep for memo usage:
grep -l "memo(function" jam-ui/src/components/client/SessionTrackGain.js jam-ui/src/components/client/JKSessionMyTrack.js
- All 6 consumer components wrapped with React.memo
- Build passes without errors
- Components have displayName for debugging
-
Build verification:
cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run buildShould complete without errors or warnings related to memo/useMemo.
-
Code verification:
# Check MixersContext memoization grep -n "useMemo" jam-ui/src/context/MixersContext.js # Check VuContext memoization grep -n "useMemo" jam-ui/src/context/VuContext.js # Check GlobalContext memoization grep -n "useMemo" jam-ui/src/context/GlobalContext.js # Check memo wrappers grep -l "memo(function" jam-ui/src/components/client/*.js -
Functional verification (manual):
- Open session in browser with React DevTools Profiler
- Move volume slider
- Verify VU meters do NOT show in Profiler re-render list
- Verify only SessionTrackGain re-renders (due to local state)
<success_criteria>
- CTX-01: MixersContext.Provider value is memoized (useMemo wraps mixerHelper)
- CTX-02: VuContext separated from MixerConfigContext (already done in Phase 28, now memoized)
- CTX-03: Context consumers only subscribe to data they actually use (React.memo prevents prop-unchanged re-renders)
- Volume slider change doesn't re-render VU meters
- VU update doesn't re-render volume sliders
- All 3 context providers use useMemo
- All 6 consumer components wrapped with React.memo
- Build passes without errors </success_criteria>