perf(workspace): gate side effects on stack route focus

Pass useIsFocused through as isRouteFocused rather than short-circuiting
the whole tree. Terminals query/subscription, checkout diff, providers
snapshot, keybindings, tab reconciliation, focused-agent writes, and
sidebar rendering all no-op when the route is in the stack but not
focused, so a hidden workspace screen no longer drives background work.
This commit is contained in:
Mohamed Boudra
2026-04-20 10:45:48 +07:00
parent 427664dfa7
commit bd748b6edc
2 changed files with 82 additions and 30 deletions
@@ -30,13 +30,19 @@ interface UseProvidersSnapshotResult {
refetchIfStale: () => void;
}
interface UseProvidersSnapshotOptions {
enabled?: boolean;
}
export function useProvidersSnapshot(
serverId: string | null,
cwd?: string | null,
options: UseProvidersSnapshotOptions = {},
): UseProvidersSnapshotResult {
const queryClient = useQueryClient();
const client = useHostRuntimeClient(serverId ?? "");
const isConnected = useHostRuntimeIsConnected(serverId ?? "");
const enabled = options.enabled ?? true;
const normalizedCwd = cwd?.trim() || undefined;
const normalizedCwdKey = normalizeProvidersSnapshotCwdKey(normalizedCwd);
const supportsSnapshot = useSessionStore(
@@ -50,7 +56,7 @@ export function useProvidersSnapshot(
const snapshotQuery = useQuery({
queryKey,
enabled: Boolean(supportsSnapshot && serverId && client && isConnected),
enabled: Boolean(enabled && supportsSnapshot && serverId && client && isConnected),
staleTime: 60_000,
queryFn: async () => {
if (!client) {
@@ -71,7 +77,7 @@ export function useProvidersSnapshot(
const { mutateAsync: refreshSnapshot, isPending: isRefreshing } = refreshMutation;
useEffect(() => {
if (!supportsSnapshot || !client || !isConnected || !serverId) {
if (!enabled || !supportsSnapshot || !client || !isConnected || !serverId) {
return;
}
@@ -89,7 +95,16 @@ export function useProvidersSnapshot(
requestId: "providers_snapshot_update",
});
});
}, [client, isConnected, normalizedCwdKey, queryClient, queryKey, serverId, supportsSnapshot]);
}, [
client,
enabled,
isConnected,
normalizedCwdKey,
queryClient,
queryKey,
serverId,
supportsSnapshot,
]);
const refresh = useCallback(
async (providers?: AgentProvider[]) => {
@@ -131,6 +131,10 @@ type WorkspaceScreenProps = {
workspaceId: string;
};
type WorkspaceScreenContentProps = WorkspaceScreenProps & {
isRouteFocused: boolean;
};
function trimNonEmpty(value: string | null | undefined): string | null {
if (typeof value !== "string") {
return null;
@@ -566,13 +570,13 @@ function useStableTabDescriptorMap(tabDescriptors: WorkspaceTabDescriptor[]) {
export function WorkspaceScreen({ serverId, workspaceId }: WorkspaceScreenProps) {
const isFocused = useIsFocused();
if (!isFocused) {
return <View style={{ flex: 1 }} />;
}
return (
<ExplorerSidebarAnimationProvider>
<WorkspaceScreenContent serverId={serverId} workspaceId={workspaceId} />
<WorkspaceScreenContent
serverId={serverId}
workspaceId={workspaceId}
isRouteFocused={isFocused}
/>
</ExplorerSidebarAnimationProvider>
);
}
@@ -604,7 +608,11 @@ function useCloseTabs(): UseCloseTabsResult {
return { closingTabIds, closeTab };
}
function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps) {
function WorkspaceScreenContent({
serverId,
workspaceId,
isRouteFocused,
}: WorkspaceScreenContentProps) {
const { theme } = useUnistyles();
const insets = useSafeAreaInsets();
const mainBackgroundColor = theme.colors.surfaceWorkspace;
@@ -646,11 +654,15 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
// Warm the server-side provider snapshot for this workspace cwd so the model
// picker is ready when opened. Consumers share the same query cache key.
useProvidersSnapshot(normalizedServerId, workspaceDirectory);
useProvidersSnapshot(normalizedServerId, workspaceDirectory, {
enabled: isRouteFocused,
});
const [pendingTerminalCreateInput, setPendingTerminalCreateInput] = useState<{
paneId?: string;
} | null>(null);
const canCreateTerminalNow = Boolean(client && isConnected && workspaceDirectory);
const canCreateTerminalNow = Boolean(
isRouteFocused && client && isConnected && workspaceDirectory,
);
const workspaceAgentVisibility = useStoreWithEqualityFn(
useSessionStore,
@@ -669,7 +681,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
type ListTerminalsPayload = ListTerminalsResponse["payload"];
const terminalsQuery = useQuery({
queryKey: terminalsQueryKey,
enabled: Boolean(client && isConnected) && Boolean(workspaceDirectory),
enabled: Boolean(isRouteFocused && client && isConnected && workspaceDirectory),
queryFn: async () => {
if (!client || !workspaceDirectory) {
throw new Error("Host is not connected");
@@ -736,7 +748,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
const { archiveAgent } = useArchiveAgent();
useEffect(() => {
if (!client || !isConnected || !workspaceDirectory) {
if (!isRouteFocused || !client || !isConnected || !workspaceDirectory) {
return;
}
@@ -758,9 +770,11 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
unsubscribeChanged();
client.unsubscribeTerminals({ cwd: workspaceDirectory });
};
}, [client, isConnected, queryClient, terminalsQueryKey, workspaceDirectory]);
}, [client, isConnected, isRouteFocused, queryClient, terminalsQueryKey, workspaceDirectory]);
const isCheckoutQueryEnabled = Boolean(client && isConnected) && Boolean(workspaceDirectory);
const isCheckoutQueryEnabled = Boolean(
isRouteFocused && client && isConnected && workspaceDirectory,
);
const checkoutQuery = useQuery({
queryKey: checkoutStatusQueryKey(
normalizedServerId,
@@ -851,8 +865,11 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
}, [isGitCheckout, normalizedServerId, workspaceDirectory]);
useEffect(() => {
if (!isRouteFocused) {
return;
}
setActiveExplorerCheckout(activeExplorerCheckout);
}, [activeExplorerCheckout, setActiveExplorerCheckout]);
}, [activeExplorerCheckout, isRouteFocused, setActiveExplorerCheckout]);
const openExplorerForWorkspace = useCallback(() => {
if (!activeExplorerCheckout) {
@@ -876,7 +893,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
});
useEffect(() => {
if (isWeb || !isExplorerOpen) {
if (!isRouteFocused || isWeb || !isExplorerOpen) {
return;
}
@@ -889,7 +906,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
});
return () => handler.remove();
}, [closeToAgent, isExplorerOpen]);
}, [closeToAgent, isExplorerOpen, isRouteFocused]);
const persistenceKey = useMemo(
() =>
@@ -979,14 +996,20 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
}, [focusedPaneTabState.activeTab]);
useEffect(() => {
if (!isRouteFocused) {
return;
}
setFocusedAgentId(normalizedServerId, focusedPaneAgentId);
}, [focusedPaneAgentId, normalizedServerId, setFocusedAgentId]);
}, [focusedPaneAgentId, isRouteFocused, normalizedServerId, setFocusedAgentId]);
useEffect(() => {
if (!isRouteFocused) {
return;
}
return () => {
setFocusedAgentId(normalizedServerId, null);
};
}, [normalizedServerId, setFocusedAgentId]);
}, [isRouteFocused, normalizedServerId, setFocusedAgentId]);
const ensureWorkspaceTab = useCallback(
function ensureWorkspaceTab(target: WorkspaceTabTarget): string | null {
@@ -1018,6 +1041,9 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
);
useEffect(() => {
if (!isRouteFocused) {
return;
}
if (!normalizedServerId || !normalizedWorkspaceId || !persistenceKey) {
return;
}
@@ -1040,6 +1066,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
});
}, [
hasHydratedAgents,
isRouteFocused,
pendingByDraftId,
persistenceKey,
reconcileWorkspaceTabs,
@@ -1077,6 +1104,9 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
const emptyWorkspaceSeedRef = useRef<string | null>(null);
const autoOpenedSetupTabWorkspaceRef = useRef<string | null>(null);
useEffect(() => {
if (!isRouteFocused) {
return;
}
if (!persistenceKey) {
return;
}
@@ -1099,12 +1129,16 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
normalizedWorkspaceId,
openWorkspaceDraftTab,
persistenceKey,
isRouteFocused,
terminals.length,
tabs.length,
workspaceAgentVisibility.activeAgentIds.size,
]);
useEffect(() => {
if (!isRouteFocused) {
return;
}
if (!persistenceKey) {
return;
}
@@ -1146,6 +1180,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
autoOpenedSetupTabWorkspaceRef.current = persistenceKey;
}, [
hasSetupTab,
isRouteFocused,
normalizedWorkspaceId,
openWorkspaceTabInBackground,
persistenceKey,
@@ -1763,7 +1798,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
"workspace.tab.navigate-relative",
"workspace.terminal.new",
] as const,
enabled: Boolean(normalizedServerId && normalizedWorkspaceId),
enabled: Boolean(isRouteFocused && normalizedServerId && normalizedWorkspaceId),
priority: 100,
isActive: () => true,
handle: handleWorkspaceTabAction,
@@ -1784,7 +1819,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
"workspace.pane.move-tab.down",
"workspace.pane.close",
] as const,
enabled: Boolean(normalizedServerId && normalizedWorkspaceId),
enabled: Boolean(isRouteFocused && normalizedServerId && normalizedWorkspaceId),
priority: 100,
isActive: () => true,
handle: handleWorkspacePaneAction,
@@ -1794,11 +1829,11 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
const canRenderDesktopPaneSplits = supportsDesktopPaneSplits();
const shouldRenderDesktopPaneFallback = !isMobile && !canRenderDesktopPaneSplits;
useEffect(() => {
if (isNative || typeof document === "undefined" || activeTabDescriptor) {
if (!isRouteFocused || isNative || typeof document === "undefined" || activeTabDescriptor) {
return;
}
document.title = "Workspace";
}, [activeTabDescriptor]);
}, [activeTabDescriptor, isRouteFocused]);
const buildPaneContentModel = useCallback(
(input: {
tab: WorkspaceTabDescriptor;
@@ -1810,7 +1845,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
tab: input.tab,
normalizedServerId,
normalizedWorkspaceId,
isPaneFocused: input.isPaneFocused,
isPaneFocused: isRouteFocused && input.isPaneFocused,
onOpenTab: (target) => {
if (!persistenceKey) {
return;
@@ -1846,6 +1881,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
[
handleCloseTabById,
handleOpenFileFromChat,
isRouteFocused,
focusWorkspacePane,
navigateToTabId,
normalizedServerId,
@@ -1919,8 +1955,8 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
<MobileMountedTabSlot
key={tabId}
tabDescriptor={tabDescriptor}
isVisible={tabId === activeTabDescriptor.tabId}
isPaneFocused={tabId === activeTabDescriptor.tabId}
isVisible={isRouteFocused && tabId === activeTabDescriptor.tabId}
isPaneFocused={isRouteFocused && tabId === activeTabDescriptor.tabId}
paneId={focusedPaneId}
buildPaneContentModel={buildMobilePaneContentModel}
/>
@@ -2029,7 +2065,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
return (
<View style={[styles.container, { backgroundColor: mainBackgroundColor }]}>
{isWeb && activeTabDescriptor ? (
{isRouteFocused && isWeb && activeTabDescriptor ? (
<WorkspaceTabPresentationResolver
tab={activeTabDescriptor}
serverId={normalizedServerId}
@@ -2303,7 +2339,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
{shouldRenderDesktopPaneFallback ? (
<WorkspaceDesktopTabsRow
paneId={focusedPaneId ?? undefined}
isFocused
isFocused={isRouteFocused}
tabs={desktopTabRowItems}
normalizedServerId={normalizedServerId}
normalizedWorkspaceId={normalizedWorkspaceId}
@@ -2374,7 +2410,8 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
</View>
</View>
{(!isFocusModeEnabled || isMobile) &&
{isRouteFocused &&
(!isFocusModeEnabled || isMobile) &&
(workspaceDirectory ? (
<ExplorerSidebar
serverId={normalizedServerId}