refactor(28-02): simplify VU helpers to use external store

- Remove useState from useVuHelpers (no React state for VU data)
- Remove updateVuState, removeVuState, updateVU3 functions
- Remove VuMeterComponent (replaced by direct DOM in SessionTrackVU)
- Expose vuStore methods via return object
- VuContext provides vuStore reference to consumers
- Keep legacy renderVU/updateVU for backward compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-03-03 20:25:48 +05:30
parent 96d8f97175
commit f8214854d9
2 changed files with 15 additions and 96 deletions

View File

@ -1,4 +1,5 @@
import React, { createContext, useContext } from 'react';
import { vuStore } from '../stores/vuStore';
import useVuHelpers from '../hooks/useVuHelpers.js';
const VuContext = createContext();
@ -6,8 +7,14 @@ const VuContext = createContext();
export const VuProvider = ({ children }) => {
const vuHelpers = useVuHelpers();
// Combine vuHelpers with vuStore for context value
const value = {
...vuHelpers,
vuStore,
};
return (
<VuContext.Provider value={vuHelpers}>
<VuContext.Provider value={value}>
{children}
</VuContext.Provider>
);

View File

@ -1,9 +1,9 @@
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback } from 'react';
import { vuStore } from '../stores/vuStore';
const logger = console;
export default function useVuHelpers() {
const [vuStates, setVuStates] = useState({});
const createQualifiedId = useCallback(mixer => {
return (mixer.mode ? 'M' : 'P') + mixer.id;
@ -93,103 +93,15 @@ export default function useVuHelpers() {
}
}, []);
// New React-like VU update function
const updateVuState = useCallback((mixerId, level, clipping = false) => {
setVuStates(prev => ({
...prev,
[mixerId]: { level, clipping }
}));
}, []);
const removeVuState = useCallback((mixerId) => {
setVuStates(prev => {
const newState = { ...prev };
delete newState[mixerId];
return newState;
});
}, []);
const updateVU3 = useCallback(
(mixer, leftValue, leftClipping, rightValue, rightClipping) => {
const fqId = createQualifiedId(mixer);
//logger.debug('useVuHelpers: updateVU3', { fqId, mixer, leftValue, rightValue });
// Update React state for declarative rendering
updateVuState(fqId, leftValue, leftClipping);
},
[createQualifiedId, updateVuState]
);
useEffect(() => {
return () => {
// Cleanup on unmount
setVuStates({});
};
}, []);
// Create a proper React component that can be used outside the hook
function VuMeterComponent({ mixerId, orientation = 'vertical', lightCount = 16, lightWidth = 15, lightHeight = 10 }) {
const vuState = vuStates[mixerId] || { level: 0, clipping: false };
const { level, clipping } = vuState;
const lights = [];
for (let i = 0; i < lightCount; i++) {
// Calculate if this light should be on based on the level
const lightThreshold = (lightCount - i) / lightCount;
const isOn = level >= lightThreshold;
let bgClass = 'vu-bg-secondary'; // Default off state
if (isOn) {
if (clipping) {
bgClass = 'vu-bg-danger'; // Red for clipping
} else {
const positionFromBottom = lightCount - 1 - i;
if (positionFromBottom >= Math.floor(lightCount * 0.75)) { // Red zone (top 25%)
bgClass = 'vu-bg-danger';
} else if (positionFromBottom >= Math.floor(lightCount * 0.5)) { // Yellow zone (middle 25%)
bgClass = 'vu-bg-warning';
} else { // Green zone (bottom 50%)
bgClass = 'vu-bg-success';
}
}
}
lights.push(
<div
key={i}
className={bgClass}
style={{
height: `${lightHeight}px`,
width: `25px`,
marginTop: '1px',
borderRadius: '2px',
border: '1px solid #eee'
}}
/>
);
}
return (
<div className='vu'>
<div className="d-flex flex-column" style={{ height: `${lightCount * (lightHeight + 1)}px` }}>
{lights}
</div>
</div>
);
}
return {
// React-like components and functions
VuMeter: VuMeterComponent,
updateVuState,
removeVuState,
vuStates,
// External store methods (new)
updateVuState: vuStore.updateLevel,
removeVuState: vuStore.removeLevel,
vuStore, // Expose full store for advanced usage
// Legacy functions for backward compatibility
createQualifiedId,
renderVU,
updateVU,
updateVU3
};
}