LibreChat/client/src
Danny Avila 7181174c3b
🖼️ fix: Message Icon Flickering from Context-Triggered Re-renders (#12489)
* perf: add custom memo comparator to MessageIcon for stable re-render gating

MessageIcon receives full `agent` and `assistant` objects as props from
useMessageActions, which recomputes them when AgentsMapContext or
AssistantsMapContext update (e.g., react-query refetch on window focus).
These context-triggered re-renders bypass MessageRender's React.memo,
producing new object references for agent/assistant even when the
underlying data is unchanged. The default shallow comparison in
MessageIcon's memo then fails, causing unnecessary re-renders that
manifest as visible icon flickering.

Add arePropsEqual comparator that checks only the fields MessageIcon
actually uses (name, avatar filepath, metadata avatar) instead of
object identity, so the component correctly bails out when icon-relevant
data hasn't changed.

* refactor: export arePropsEqual, drop redundant useMemos, add JSDoc

- Export arePropsEqual so it can be tested in isolation
- Add JSDoc documenting which fields are intentionally omitted (id)
  and why iconData uses reference equality
- Replace five trivial useMemo calls (agent?.name ?? '', etc.) with
  direct computed values — the custom comparator already gates
  re-renders, so these memos only add closure/dep-array overhead
  without ever providing cache hits
- Remove unused React import

* test: add unit tests for MessageIcon arePropsEqual comparator

Exercise the custom memo comparator to ensure:
- New object references with same display fields are treated as equal
- Changed name or avatar filepath triggers re-render
- iconData reference change triggers re-render
- undefined→defined agent with undefined fields is treated as equal

* fix: replace nested ternary with if-else for eslint compliance

* test: add comment on subtle equality invariant and defined→undefined case

* perf: compare iconData by field values instead of reference

iconData is a useMemo'd object from the parent, but comparing by
reference still causes unnecessary re-renders when the parent
recomputes the memo with identical primitive values. Compare all
five fields individually (endpoint, model, iconURL, modelLabel,
isCreatedByUser) for consistency with how agent/assistant are handled.
2026-03-31 18:24:18 -04:00
..
@types 🧩 feat: Redesign Tool Call UI with Contextual Icons, Smart Grouping, and Rich Output Rendering (#12163) 2026-03-25 12:31:39 -04:00
a11y ⚗️ feat: Agent Context Compaction/Summarization (#12287) 2026-03-21 14:28:56 -04:00
common 🪢 refactor: Eliminate Unnecessary Re-renders During Message Streaming (#12454) 2026-03-29 17:05:12 -04:00
components 🖼️ fix: Message Icon Flickering from Context-Triggered Re-renders (#12489) 2026-03-31 18:24:18 -04:00
constants 🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804) 2025-08-13 16:24:17 -04:00
data-provider 📁 refactor: Prompts UI (#11570) 2026-03-22 16:56:22 -04:00
hooks 🪢 refactor: Eliminate Unnecessary Re-renders During Message Streaming (#12454) 2026-03-29 17:05:12 -04:00
locales 🌍 i18n: Update translation.json with latest translations (#12458) 2026-03-29 18:43:43 -04:00
Providers 🪝 fix: Safe Hook Fallbacks for Tool-Call Components in Search Route (#12423) 2026-03-26 16:40:37 -04:00
routes 📁 refactor: Prompts UI (#11570) 2026-03-22 16:56:22 -04:00
store 🧩 feat: Redesign Tool Call UI with Contextual Icons, Smart Grouping, and Rich Output Rendering (#12163) 2026-03-25 12:31:39 -04:00
utils 🧩 feat: Redesign Tool Call UI with Contextual Icons, Smart Grouping, and Rich Output Rendering (#12163) 2026-03-25 12:31:39 -04:00
App.jsx 🛜 feat: Enable Network Requests in Offline Mode (#11107) 2025-12-26 09:01:27 -05:00
main.jsx
mobile.css 🎨 refactor: Redesign Sidebar with Unified Icon Strip Layout (#12013) 2026-03-22 01:15:20 -04:00
style.css 🧩 feat: Redesign Tool Call UI with Contextual Icons, Smart Grouping, and Rich Output Rendering (#12163) 2026-03-25 12:31:39 -04:00
vite-env.d.ts