From 468860d54fce2b546596379f25ebe715867dce47 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Thu, 5 Mar 2026 17:22:30 +0530 Subject: [PATCH] fix(29): revise plan based on checker feedback - Split Task 1 into Task 1a (stabilize useMixerHelper) and Task 1b (memoize MixersContext) - Add useMixerHelper.js to files_modified - Add getMixer useCallback wrapping as prerequisite for context memoization - Add key_link verifying useMixerHelper -> MixersContext wiring - Add CTX-00 success criterion for getMixer stabilization Issues addressed: - task_completeness: Task 1 now includes getMixer useCallback wrapping - key_links_planned: Added verification for useMixerHelper stabilization --- .../29-context-optimization/29-01-PLAN.md | 76 ++++++++++++++++++- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/.planning/phases/29-context-optimization/29-01-PLAN.md b/.planning/phases/29-context-optimization/29-01-PLAN.md index 66420a1b5..0a001f675 100644 --- a/.planning/phases/29-context-optimization/29-01-PLAN.md +++ b/.planning/phases/29-context-optimization/29-01-PLAN.md @@ -5,6 +5,7 @@ type: execute wave: 1 depends_on: [] files_modified: + - jam-ui/src/hooks/useMixerHelper.js - jam-ui/src/context/MixersContext.js - jam-ui/src/context/VuContext.js - jam-ui/src/context/GlobalContext.js @@ -22,7 +23,11 @@ must_haves: - "VU update does not re-render volume sliders" - "MixersContext.Provider value is memoized" - "Context consumers only re-render when their specific data changes" + - "useMixerHelper returns stable function references" artifacts: + - path: "jam-ui/src/hooks/useMixerHelper.js" + provides: "Stable function references via useCallback" + contains: "useCallback" - path: "jam-ui/src/context/MixersContext.js" provides: "Memoized context provider value" contains: "useMemo" @@ -36,6 +41,10 @@ must_haves: provides: "Memoized context consumer" contains: "memo" key_links: + - from: "useMixerHelper.js" + to: "MixersContext.js" + via: "stable getMixer function" + pattern: "const getMixer = useCallback" - from: "MixersContext.Provider" to: "useMixerHelper" via: "useMemo wrapper" @@ -69,13 +78,70 @@ Output: Memoized context providers (MixersContext, VuContext, GlobalContext) and - Task 1: Memoize MixersContext provider value + Task 1a: Stabilize useMixerHelper function references + + jam-ui/src/hooks/useMixerHelper.js + + +Wrap internal functions in useMixerHelper.js with useCallback to ensure stable references. Without this, memoizing MixersContext.Provider value is ineffective because the mixerHelper object changes every render. + +**CRITICAL: The `getMixer` function (line 128) is NOT wrapped with useCallback. This causes ALL dependent functions to recreate every render.** + +1. Wrap `getMixer` with useCallback: + ```javascript + const getMixer = useCallback((mixerId, mode) => { + // Only default to mixMode if mode is undefined, not if it's explicitly false + if (mode === undefined) { + mode = mixMode; + } + return allMixersRef.current[(mode ? 'M' : 'P') + mixerId]; + }, [mixMode]); + ``` + Note: Uses `allMixersRef.current` (ref, not dependency) and `mixMode` (selector value). + +2. Verify these functions are already wrapped (they should be - just confirm): + - `fillTrackVolumeObject` (line 136) - uses useCallback, depends on getMixer + - `setMixerVolume` (line 176) - uses useCallback + - `mediaMixers` (line 216) - uses useCallback + - `updateMixerData` (line 235) - uses useCallback + - `getMixerByTrackId` (line 353) - uses useCallback + - `groupedMixersForClientId` (line 369) - uses useCallback + - `findMixerForTrack` (line 397) - uses useCallback + - `mixersForGroupId` (line 592) - uses useCallback + - `getGroupMixer` (line 608) - uses useCallback + - `getMixerByResourceId` (line 705) - uses useCallback + - `mute` (line 721) - uses useCallback, depends on getMixer + - `faderChanged` (line 751) - uses useCallback, depends on getMixer + - `panChanged` (line 811) - uses useCallback, depends on getMixer + - `loopChanged` (line 835) - uses useCallback, depends on getMixer + - `updateVU` (line 896) - uses useCallback, depends on getMixer + - `refreshMixer` (line 928) - uses useCallback, depends on getMixer + +3. After wrapping getMixer, these dependent functions will automatically stabilize because their `getMixer` dependency will now be stable. + +**Why this matters:** Without stable `getMixer`, the dependency chain causes 10+ functions to recreate every render, defeating context memoization. + + +1. Run `grep -n "const getMixer = useCallback" jam-ui/src/hooks/useMixerHelper.js` - should find the wrapped function +2. Run `cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build` - should compile without errors + + +- getMixer is wrapped with useCallback +- All dependent functions now have stable references +- Build passes without errors + + + + + Task 1b: Memoize MixersContext provider value jam-ui/src/context/MixersContext.js Memoize the MixersContext.Provider value to prevent new object creation on every render. +**PREREQUISITE:** Task 1a must be complete - useMixerHelper must return stable references for this memoization to be effective. + 1. Import `useMemo` from 'react' 2. Wrap the `mixerHelper` value with `useMemo`: ```javascript @@ -83,9 +149,7 @@ Memoize the MixersContext.Provider value to prevent new object creation on every ``` 3. Pass `value` to `MixersContext.Provider` instead of `mixerHelper` directly -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). +Now that useMixerHelper returns stable function references (after Task 1a), the memoized context value will only change when actual data changes (allMixers, mixMode, etc.), not on every render. 1. Run `cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build` - should compile without errors @@ -222,6 +286,9 @@ After all tasks complete: 2. **Code verification:** ```bash + # Check useMixerHelper getMixer stabilization + grep -n "const getMixer = useCallback" jam-ui/src/hooks/useMixerHelper.js + # Check MixersContext memoization grep -n "useMemo" jam-ui/src/context/MixersContext.js @@ -243,6 +310,7 @@ After all tasks complete: +- CTX-00: useMixerHelper.getMixer is wrapped with useCallback (prerequisite for CTX-01) - 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)