perf(renderer): cache repeated team badge selectors

This commit is contained in:
777genius 2026-05-31 05:28:10 +03:00
parent 93a45e0823
commit 5041c79916
3 changed files with 35 additions and 1 deletions

View file

@ -210,12 +210,14 @@ interface SidebarTeamsDerived {
} }
let cachedSidebarTeamsSignature: string | null = null; let cachedSidebarTeamsSignature: string | null = null;
let cachedSidebarTeamsSource: readonly TeamSummary[] | null = null;
let cachedSidebarTeamsDerived: SidebarTeamsDerived = { let cachedSidebarTeamsDerived: SidebarTeamsDerived = {
identityKey: '', identityKey: '',
filterTeams: [], filterTeams: [],
statusSummaries: [], statusSummaries: [],
memberColorByTeam: new Map(), memberColorByTeam: new Map(),
}; };
let cachedLeadOfflineTeamsSource: Partial<Record<string, LeadActivityState>> | null = null;
let cachedLeadOfflineTeamsSignature = ''; let cachedLeadOfflineTeamsSignature = '';
let cachedLeadOfflineTeamNames: string[] = []; let cachedLeadOfflineTeamNames: string[] = [];
@ -255,6 +257,10 @@ function buildTeamNamesIdentityKey(teams: readonly TeamSummary[]): string {
function selectLeadOfflineTeamNames( function selectLeadOfflineTeamNames(
leadActivityByTeam: Partial<Record<string, LeadActivityState>> leadActivityByTeam: Partial<Record<string, LeadActivityState>>
): string[] { ): string[] {
if (leadActivityByTeam === cachedLeadOfflineTeamsSource) {
return cachedLeadOfflineTeamNames;
}
const offlineTeamNames: string[] = []; const offlineTeamNames: string[] = [];
for (const [teamName, activity] of Object.entries(leadActivityByTeam)) { for (const [teamName, activity] of Object.entries(leadActivityByTeam)) {
if (activity === 'offline') { if (activity === 'offline') {
@ -269,17 +275,24 @@ function selectLeadOfflineTeamNames(
} }
if (signature === cachedLeadOfflineTeamsSignature) { if (signature === cachedLeadOfflineTeamsSignature) {
cachedLeadOfflineTeamsSource = leadActivityByTeam;
return cachedLeadOfflineTeamNames; return cachedLeadOfflineTeamNames;
} }
cachedLeadOfflineTeamsSource = leadActivityByTeam;
cachedLeadOfflineTeamsSignature = signature; cachedLeadOfflineTeamsSignature = signature;
cachedLeadOfflineTeamNames = offlineTeamNames; cachedLeadOfflineTeamNames = offlineTeamNames;
return cachedLeadOfflineTeamNames; return cachedLeadOfflineTeamNames;
} }
function selectSidebarTeamsDerived(teams: readonly TeamSummary[]): SidebarTeamsDerived { function selectSidebarTeamsDerived(teams: readonly TeamSummary[]): SidebarTeamsDerived {
if (teams === cachedSidebarTeamsSource) {
return cachedSidebarTeamsDerived;
}
const signature = buildSidebarTeamsSignature(teams); const signature = buildSidebarTeamsSignature(teams);
if (signature === cachedSidebarTeamsSignature) { if (signature === cachedSidebarTeamsSignature) {
cachedSidebarTeamsSource = teams;
return cachedSidebarTeamsDerived; return cachedSidebarTeamsDerived;
} }
@ -290,6 +303,7 @@ function selectSidebarTeamsDerived(teams: readonly TeamSummary[]): SidebarTeamsD
} }
} }
cachedSidebarTeamsSource = teams;
cachedSidebarTeamsSignature = signature; cachedSidebarTeamsSignature = signature;
cachedSidebarTeamsDerived = { cachedSidebarTeamsDerived = {
identityKey: buildTeamNamesIdentityKey(teams), identityKey: buildTeamNamesIdentityKey(teams),

View file

@ -34,6 +34,18 @@ interface MemberBadgeProps {
} }
const EMPTY_TEAM_MEMBERS: readonly ResolvedTeamMember[] = []; const EMPTY_TEAM_MEMBERS: readonly ResolvedTeamMember[] = [];
const memberAvatarMapCache = new WeakMap<readonly ResolvedTeamMember[], Map<string, string>>();
function getCachedMemberAvatarMap(members: readonly ResolvedTeamMember[]): Map<string, string> {
const cached = memberAvatarMapCache.get(members);
if (cached) {
return cached;
}
const next = buildMemberAvatarMap(members);
memberAvatarMapCache.set(members, next);
return next;
}
/** /**
* Reusable member avatar + colored name badge. * Reusable member avatar + colored name badge.
@ -61,7 +73,7 @@ export const MemberBadge = memo(
? selectResolvedMembersForTeamName(s, effectiveAvatarTeamName) ? selectResolvedMembersForTeamName(s, effectiveAvatarTeamName)
: EMPTY_TEAM_MEMBERS : EMPTY_TEAM_MEMBERS
); );
const avatarMap = useMemo(() => buildMemberAvatarMap(teamMembers), [teamMembers]); const avatarMap = useMemo(() => getCachedMemberAvatarMap(teamMembers), [teamMembers]);
const avatarSize = size === 'md' ? 32 : size === 'sm' ? 24 : 18; const avatarSize = size === 'md' ? 32 : size === 'sm' ? 24 : 18;
const avatarClass = size === 'md' ? 'size-6' : size === 'sm' ? 'size-5' : 'size-4'; const avatarClass = size === 'md' ? 'size-6' : size === 'sm' ? 'size-5' : 'size-4';
const textClass = size === 'md' ? 'text-xs' : size === 'sm' ? 'text-[10px]' : 'text-[9px]'; const textClass = size === 'md' ? 'text-xs' : size === 'sm' ? 'text-[10px]' : 'text-[9px]';

View file

@ -114,6 +114,7 @@ interface TeamMentionEntry {
} }
let cachedTeamMentionSignature = ''; let cachedTeamMentionSignature = '';
let cachedTeamMentionSource: readonly TeamSummary[] | null = null;
let cachedTeamMentionMeta: TeamMentionMeta = { let cachedTeamMentionMeta: TeamMentionMeta = {
teamNames: EMPTY_TEAM_NAMES, teamNames: EMPTY_TEAM_NAMES,
teamColorByName: EMPTY_TEAM_COLOR_MAP, teamColorByName: EMPTY_TEAM_COLOR_MAP,
@ -142,8 +143,13 @@ function getTeamMentionSignature(teams: readonly TeamSummary[]): string {
} }
function selectMessagesPanelTeamMentionMeta(teams: readonly TeamSummary[]): TeamMentionMeta { function selectMessagesPanelTeamMentionMeta(teams: readonly TeamSummary[]): TeamMentionMeta {
if (teams === cachedTeamMentionSource) {
return cachedTeamMentionMeta;
}
const signature = getTeamMentionSignature(teams); const signature = getTeamMentionSignature(teams);
if (signature === cachedTeamMentionSignature) { if (signature === cachedTeamMentionSignature) {
cachedTeamMentionSource = teams;
return cachedTeamMentionMeta; return cachedTeamMentionMeta;
} }
@ -157,6 +163,7 @@ function selectMessagesPanelTeamMentionMeta(teams: readonly TeamSummary[]): Team
.sort(compareTeamMentionEntries); .sort(compareTeamMentionEntries);
if (entries.length === 0) { if (entries.length === 0) {
cachedTeamMentionSource = teams;
cachedTeamMentionSignature = signature; cachedTeamMentionSignature = signature;
cachedTeamMentionMeta = { cachedTeamMentionMeta = {
teamNames: EMPTY_TEAM_NAMES, teamNames: EMPTY_TEAM_NAMES,
@ -180,6 +187,7 @@ function selectMessagesPanelTeamMentionMeta(teams: readonly TeamSummary[]): Team
} }
} }
cachedTeamMentionSource = teams;
cachedTeamMentionSignature = signature; cachedTeamMentionSignature = signature;
cachedTeamMentionMeta = { teamNames, teamColorByName }; cachedTeamMentionMeta = { teamNames, teamColorByName };
return cachedTeamMentionMeta; return cachedTeamMentionMeta;