Reduce workspace render churn
This commit is contained in:
@@ -50,7 +50,6 @@ interface SidebarAnimationContextValue {
|
||||
animateToClose: () => void;
|
||||
startMobilePanelTransition: (mobileView: "agent" | "agent-list" | "file-explorer") => void;
|
||||
settleMobilePanel: (mobileView: "agent" | "agent-list" | "file-explorer") => void;
|
||||
settledGeneration: number;
|
||||
isGesturing: SharedValue<boolean>;
|
||||
mobileVisualPanel: SharedValue<number>;
|
||||
mobilePanelState: SharedValue<number>;
|
||||
@@ -61,6 +60,10 @@ interface SidebarAnimationContextValue {
|
||||
|
||||
const SidebarAnimationContext = createContext<SidebarAnimationContextValue | null>(null);
|
||||
|
||||
// Separate context so that settle-driven re-renders only reach MobileSidebar,
|
||||
// not every other useSidebarAnimation() consumer.
|
||||
const SidebarSettledGenerationContext = createContext<number>(0);
|
||||
|
||||
function getMobileVisualPanel(mobileView: "agent" | "agent-list" | "file-explorer"): number {
|
||||
if (mobileView === "agent-list") {
|
||||
return MOBILE_VISUAL_PANEL_AGENT_LIST;
|
||||
@@ -357,7 +360,6 @@ export function SidebarAnimationProvider({ children }: { children: ReactNode })
|
||||
animateToClose,
|
||||
startMobilePanelTransition,
|
||||
settleMobilePanel,
|
||||
settledGeneration,
|
||||
isGesturing,
|
||||
mobileVisualPanel,
|
||||
mobilePanelState,
|
||||
@@ -373,7 +375,6 @@ export function SidebarAnimationProvider({ children }: { children: ReactNode })
|
||||
animateToClose,
|
||||
startMobilePanelTransition,
|
||||
settleMobilePanel,
|
||||
settledGeneration,
|
||||
isGesturing,
|
||||
mobileVisualPanel,
|
||||
mobilePanelState,
|
||||
@@ -384,7 +385,11 @@ export function SidebarAnimationProvider({ children }: { children: ReactNode })
|
||||
);
|
||||
|
||||
return (
|
||||
<SidebarAnimationContext.Provider value={value}>{children}</SidebarAnimationContext.Provider>
|
||||
<SidebarAnimationContext.Provider value={value}>
|
||||
<SidebarSettledGenerationContext.Provider value={settledGeneration}>
|
||||
{children}
|
||||
</SidebarSettledGenerationContext.Provider>
|
||||
</SidebarAnimationContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -395,3 +400,7 @@ export function useSidebarAnimation() {
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
export function useSidebarSettledGeneration() {
|
||||
return useContext(SidebarSettledGenerationContext);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useSyncExternalStore,
|
||||
type ReactNode,
|
||||
@@ -57,22 +58,27 @@ export function useVoice() {
|
||||
export function useVoiceOptional(): VoiceContextValue | null {
|
||||
const runtime = useContext(VoiceRuntimeContext);
|
||||
const snapshot = useSyncExternalStore(
|
||||
runtime ? runtime.subscribe.bind(runtime) : noopSubscribe,
|
||||
runtime ? runtime.getSnapshot.bind(runtime) : getEmptySnapshot,
|
||||
runtime ? runtime.getSnapshot.bind(runtime) : getEmptySnapshot,
|
||||
runtime ? runtime.subscribe : noopSubscribe,
|
||||
runtime ? runtime.getSnapshot : getEmptySnapshot,
|
||||
runtime ? runtime.getSnapshot : getEmptySnapshot,
|
||||
);
|
||||
|
||||
if (!runtime) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...snapshot,
|
||||
startVoice: runtime.startVoice.bind(runtime),
|
||||
stopVoice: runtime.stopVoice.bind(runtime),
|
||||
isVoiceModeForAgent: runtime.isVoiceModeForAgent.bind(runtime),
|
||||
toggleMute: runtime.toggleMute.bind(runtime),
|
||||
};
|
||||
// Methods on the runtime object literal close over factory-local state; they
|
||||
// don't use `this`, so no binding is needed. Memoising on [snapshot, runtime]
|
||||
// keeps the returned object reference stable across re-renders that don't
|
||||
// change either, preventing downstream memo/useMemo misses.
|
||||
return useMemo(() => {
|
||||
if (!runtime) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
...snapshot,
|
||||
startVoice: runtime.startVoice,
|
||||
stopVoice: runtime.stopVoice,
|
||||
isVoiceModeForAgent: runtime.isVoiceModeForAgent,
|
||||
toggleMute: runtime.toggleMute,
|
||||
};
|
||||
}, [snapshot, runtime]);
|
||||
}
|
||||
|
||||
export function useVoiceTelemetry() {
|
||||
|
||||
Reference in New Issue
Block a user