perf: use shallow selectors in useAggregatedAgents to reduce re-renders
Replace greedy sessions selector with granular useShallow selectors that only extract agent Maps and methods. This prevents HomeScreen from re-rendering on every agent stream update. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
import { useMemo, useCallback } from "react";
|
import { useMemo, useCallback } from "react";
|
||||||
|
import { useShallow } from "zustand/shallow";
|
||||||
import { useDaemonConnections } from "@/contexts/daemon-connections-context";
|
import { useDaemonConnections } from "@/contexts/daemon-connections-context";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
import type { AgentDirectoryEntry } from "@/types/agent-directory";
|
import type { AgentDirectoryEntry } from "@/types/agent-directory";
|
||||||
|
import type { Agent } from "@/stores/session-store";
|
||||||
|
|
||||||
export interface AggregatedAgent extends AgentDirectoryEntry {
|
export interface AggregatedAgent extends AgentDirectoryEntry {
|
||||||
serverId: string;
|
serverId: string;
|
||||||
@@ -18,28 +20,47 @@ export interface AggregatedAgentsResult {
|
|||||||
|
|
||||||
export function useAggregatedAgents(): AggregatedAgentsResult {
|
export function useAggregatedAgents(): AggregatedAgentsResult {
|
||||||
const { connectionStates } = useDaemonConnections();
|
const { connectionStates } = useDaemonConnections();
|
||||||
const sessions = useSessionStore((state) => state.sessions);
|
|
||||||
|
const sessionAgents = useSessionStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
const result: Record<string, Map<string, Agent> | undefined> = {};
|
||||||
|
for (const [serverId, session] of Object.entries(state.sessions)) {
|
||||||
|
result[serverId] = session.agents;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const sessionMethods = useSessionStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
const result: Record<string, NonNullable<typeof state.sessions[string]["methods"]> | undefined> = {};
|
||||||
|
for (const [serverId, session] of Object.entries(state.sessions)) {
|
||||||
|
result[serverId] = session.methods ?? undefined;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const refreshAll = useCallback(() => {
|
const refreshAll = useCallback(() => {
|
||||||
console.log('[useAggregatedAgents] Manual refresh triggered for all sessions');
|
console.log('[useAggregatedAgents] Manual refresh triggered for all sessions');
|
||||||
for (const [serverId, session] of Object.entries(sessions)) {
|
for (const [serverId, methods] of Object.entries(sessionMethods)) {
|
||||||
if (session?.methods?.refreshSession) {
|
if (methods?.refreshSession) {
|
||||||
console.log(`[useAggregatedAgents] Refreshing session ${serverId}`);
|
console.log(`[useAggregatedAgents] Refreshing session ${serverId}`);
|
||||||
session.methods.refreshSession();
|
methods.refreshSession();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [sessions]);
|
}, [sessionMethods]);
|
||||||
|
|
||||||
const result = useMemo(() => {
|
const result = useMemo(() => {
|
||||||
const allAgents: AggregatedAgent[] = [];
|
const allAgents: AggregatedAgent[] = [];
|
||||||
|
|
||||||
// Derive agent directory from all sessions
|
// Derive agent directory from all sessions
|
||||||
for (const [serverId, session] of Object.entries(sessions)) {
|
for (const [serverId, agents] of Object.entries(sessionAgents)) {
|
||||||
if (!session?.agents || session.agents.size === 0) {
|
if (!agents || agents.size === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const serverLabel = connectionStates.get(serverId)?.daemon.label ?? serverId;
|
const serverLabel = connectionStates.get(serverId)?.daemon.label ?? serverId;
|
||||||
for (const agent of session.agents.values()) {
|
for (const agent of agents.values()) {
|
||||||
// Use agent's own lastActivityAt field directly
|
// Use agent's own lastActivityAt field directly
|
||||||
allAgents.push({
|
allAgents.push({
|
||||||
id: agent.id,
|
id: agent.id,
|
||||||
@@ -135,7 +156,7 @@ export function useAggregatedAgents(): AggregatedAgentsResult {
|
|||||||
isInitialLoad,
|
isInitialLoad,
|
||||||
isRevalidating,
|
isRevalidating,
|
||||||
};
|
};
|
||||||
}, [sessions, connectionStates]);
|
}, [sessionAgents, connectionStates]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
|
|||||||
Reference in New Issue
Block a user