Perf: Frontend whole-store subscriptions + no list virtualization #87

Closed
opened 2026-07-08 02:40:33 +00:00 by icub3d · 1 comment
Owner

Category: Performance (frontend) — found in code review 2026-07-07.

Problem

  • client/src/components/layout/AppShell.tsx:16 (and App.tsx:28) subscribe to entire Zustand stores with no selector, so the whole subtree re-renders on every store mutation — every MESSAGE_CREATE, reaction, typing/loading toggle. The whole chat UI reconciles on each incoming WS event.
  • MessageList.tsx:69 / MemberList.tsx:45 render every item with no windowing; MessageItem is not memoized, so a new message re-renders every existing item.
  • MemberList.tsx:32 re-sorts on every render (unmemoized); MessageItem.tsx:39 effect depends on message.thread object identity so it re-fetches on any unrelated message update.

Fix

  • Use narrow selectors (useServerStore(s => s.channels)) or useShallow for grouped slices.
  • React.memo(MessageItem); add windowing (@tanstack/react-virtual) for message + member lists.
  • Memoize the member sort; depend on message.thread?.thread_id/reply_count primitives in the effect.
**Category: Performance (frontend)** — found in code review 2026-07-07. ## Problem - `client/src/components/layout/AppShell.tsx:16` (and `App.tsx:28`) subscribe to entire Zustand stores with no selector, so the whole subtree re-renders on *every* store mutation — every `MESSAGE_CREATE`, reaction, typing/loading toggle. The whole chat UI reconciles on each incoming WS event. - `MessageList.tsx:69` / `MemberList.tsx:45` render every item with no windowing; `MessageItem` is not memoized, so a new message re-renders every existing item. - `MemberList.tsx:32` re-sorts on every render (unmemoized); `MessageItem.tsx:39` effect depends on `message.thread` object identity so it re-fetches on any unrelated message update. ## Fix - [ ] Use narrow selectors (`useServerStore(s => s.channels)`) or `useShallow` for grouped slices. - [ ] `React.memo(MessageItem)`; add windowing (`@tanstack/react-virtual`) for message + member lists. - [ ] Memoize the member sort; depend on `message.thread?.thread_id`/`reply_count` primitives in the effect.
Author
Owner

Landed on main via #107 (commit e305ed3): useShallow selectors, React.memo(MessageItem) with primitive effect deps, @tanstack/react-virtual windowing for message/member lists, memoized member sort, sorted-insert on MESSAGE_CREATE.

Landed on main via #107 (commit e305ed3): useShallow selectors, React.memo(MessageItem) with primitive effect deps, @tanstack/react-virtual windowing for message/member lists, memoized member sort, sorted-insert on MESSAGE_CREATE.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
icub3d/decentcom#87
No description provided.