perf(desktop): memoize PlatformAvatar + StatusDot to kill messaging churn

The sidebar's messaging section renders one PlatformAvatar (labelIcon) and
StatusDot per platform group. The sidebar re-renders on every streaming tick
($sessions/$workingSessionIds/$messagingSessions churn), and both leaves were
unmemoized — so every platform's avatar + dot re-rendered on each delta even
though their props (platformId/tone/className) never changed.

- PlatformAvatar: memo(forwardRef(...)) — pure fn of platformId/name/class/style
- StatusDot: memo() — pure fn of tone/class

Measured (Messaging open, settled, 2 sessions streaming, 3s window):
  before: 96 wasted (PlatformAvatar 32, StatusDot 32, + brand icons)
  after:  0 wasted

Both are shared primitives; the memo also helps every other consumer
(session rows, gateway menu, session tiles) that renders them under a hot
parent.
This commit is contained in:
Brooklyn Nicholson 2026-07-28 20:51:04 -05:00
parent f088fa5070
commit d76c7f5409
2 changed files with 41 additions and 38 deletions

View file

@ -13,7 +13,7 @@ import {
SiWhatsapp
} from '@icons-pack/react-simple-icons'
import type { ComponentPropsWithoutRef, ComponentType, SVGProps } from 'react'
import { forwardRef } from 'react'
import { forwardRef, memo } from 'react'
import { Globe, Link as LinkIcon, MessageSquareText } from '@/lib/icons'
import { cn } from '@/lib/utils'
@ -82,48 +82,50 @@ interface PlatformAvatarProps extends Omit<ComponentPropsWithoutRef<'span'>, 'ch
// component and injects a ref plus pointer/focus/aria handlers onto it. A
// plain function component with no ref/rest forwarding drops all of that
// silently — the tooltip renders but never opens (#67500).
export const PlatformAvatar = forwardRef<HTMLSpanElement, PlatformAvatarProps>(function PlatformAvatar(
{ className, platformId, platformName, style, ...rest },
ref
) {
const spec = PLATFORM_ICONS[platformId]
export const PlatformAvatar = memo(
forwardRef<HTMLSpanElement, PlatformAvatarProps>(function PlatformAvatar(
{ className, platformId, platformName, style, ...rest },
ref
) {
const spec = PLATFORM_ICONS[platformId]
const baseClass = cn(
'inline-grid size-6 shrink-0 place-items-center rounded-md text-[length:var(--conversation-caption-font-size)] font-medium',
className
)
const baseClass = cn(
'inline-grid size-6 shrink-0 place-items-center rounded-md text-[length:var(--conversation-caption-font-size)] font-medium',
className
)
if (!spec) {
return (
<span
aria-hidden="true"
className={cn(baseClass, 'bg-(--ui-bg-tertiary) text-(--ui-text-tertiary)')}
ref={ref}
style={style}
{...rest}
>
{platformName.charAt(0).toUpperCase()}
</span>
)
}
const { Icon, color } = spec
if (!spec) {
return (
<span
aria-hidden="true"
className={cn(baseClass, 'bg-(--ui-bg-tertiary) text-(--ui-text-tertiary)')}
className={baseClass}
ref={ref}
style={style}
style={{
// 16% tint of the brand color so the glyph reads against any surface
// without the avatar dominating the row.
backgroundColor: `color-mix(in srgb, ${color} 16%, transparent)`,
color,
...style
}}
{...rest}
>
{platformName.charAt(0).toUpperCase()}
{Icon ? <Icon className="size-3.5" /> : spec.monogram || platformName.charAt(0).toUpperCase()}
</span>
)
}
const { Icon, color } = spec
return (
<span
aria-hidden="true"
className={baseClass}
ref={ref}
style={{
// 16% tint of the brand color so the glyph reads against any surface
// without the avatar dominating the row.
backgroundColor: `color-mix(in srgb, ${color} 16%, transparent)`,
color,
...style
}}
{...rest}
>
{Icon ? <Icon className="size-3.5" /> : spec.monogram || platformName.charAt(0).toUpperCase()}
</span>
)
})
})
)

View file

@ -1,4 +1,5 @@
import type { ComponentProps } from 'react'
import { memo } from 'react'
import { cn } from '@/lib/utils'
@ -15,7 +16,7 @@ interface StatusDotProps extends ComponentProps<'span'> {
tone: StatusTone
}
export function StatusDot({ className, tone, ...props }: StatusDotProps) {
export const StatusDot = memo(function StatusDot({ className, tone, ...props }: StatusDotProps) {
return (
<span
aria-hidden="true"
@ -23,4 +24,4 @@ export function StatusDot({ className, tone, ...props }: StatusDotProps) {
{...props}
/>
)
}
})