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

View file

@ -34,6 +34,18 @@ interface MemberBadgeProps {
}
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.
@ -61,7 +73,7 @@ export const MemberBadge = memo(
? selectResolvedMembersForTeamName(s, effectiveAvatarTeamName)
: 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 avatarClass = size === 'md' ? 'size-6' : size === 'sm' ? 'size-5' : 'size-4';
const textClass = size === 'md' ? 'text-xs' : size === 'sm' ? 'text-[10px]' : 'text-[9px]';

View file

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