fix(perf): stop ConversationList from subscribing to all room state#377
Merged
fix(perf): stop ConversationList from subscribing to all room state#377
Conversation
ConversationList and ArchiveList called useRoom() but only used setActiveRoom and getRoom from it. useRoom() subscribes to ~15 room store values (activeRoom, activeMessages, allRooms, joinedRooms, roomsWithUnreadCount, totalMentionsCount, etc.). During background MAM sync, rapid room store updates caused 500+ ConversationList re-renders per second, triggering the render loop detector and freezing the app on Linux. Replace useRoom() with direct roomStore.getState() callbacks. Both actions are store reads with no reactive subscription needed.
mremond
added a commit
that referenced
this pull request
May 4, 2026
) Follow-up to [#377](#377) — extends the same fix pattern to other components that called heavyweight hooks for a few actions and ended up subscribed to ~15 store values each (`activeRoom`, `activeMessages`, `joinedRooms`, `roomsWithUnreadCount`, `drafts` Map, MAM states, etc.). They re-rendered on every chat/room store update during background MAM sync — same render-loop pressure that produced the original Linux freeze. ### SDK - Add `useRoomActions()` and `useChatActions()` — action-only counterparts to `useRoom()`/`useChat()` with **zero** store subscriptions. Actions are read directly via `*Store.getState()` in stable `useCallback`s. ### Always-mounted components (highest impact) - **CommandPalette**: split into wrapper + content. Wrapper returns `null` when closed so the heavy hooks (`useChat`, `useRoom`, `useRoster`) only subscribe while the palette is visible. - **InviteToRoomModal**: same wrapper/content split. - **MemberList** (right sidebar): swap `useChat()` for the existing focused `useChatActive()`. Only needed `activeConversation`. - **RoomsList** (main sidebar): replace `useRoom()` with focused `useRoomStore` selectors for `allRooms` / `activeRoomJid` + `useRoomActions()` for actions. Push the `drafts` Map subscription down to per-item via a `useRoomStore` selector inside `RoomItem` (same pattern as `ConversationItem`), so a draft change in one room only re-renders that row.
mremond
added a commit
that referenced
this pull request
May 4, 2026
…or / ContactItem) (#379) ## Summary Polish PR following [#377](#377) and [#378](#378). Closes the remaining low-/medium-impact callers identified in the audit so that no live component pulls a full `useChat()` / `useRoom()` / `useAdmin()` just for one or two values. ### SDK - New `useAdminPermissions()` — focused subscription returning `{ isAdmin, hasUserCommands, canManageUser }` only. Avoids the ~15 admin store subscriptions that `useAdmin()` makes (sessions, command queues, user/room lists, vhosts, pagination…). - Extracted `USER_COMMANDS` into a shared `adminCommands.ts` so `useAdmin` and `useAdminPermissions` share the source of truth. ### App - **ContactItem** (each row in `ContactList`): swap `useAdmin()` for `useAdminPermissions()`. Each row previously had a full admin-store subscription, so any unrelated admin update re-rendered every contact in the list. - **ContactSelector** (mounted inside `CreateRoomModal`, `CreateQuickChatModal`, `InviteToRoomModal`, `RoomMembersModal`): drop `useChat()` in favour of a focused `useChatStore` selector for `conversations`. - **RoomConfigModal**: drop `useAdmin()` in favour of a `useCallback` wrapper around `client.admin.fetchRoomOptions` via `useXMPP()`. Only `getRoomOptions` was used. Tests updated for the new mock surface. Full suite passes (5 999 tests, 0 regressions).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ConversationListandArchiveListcalleduseRoom()but only usedsetActiveRoomandgetRoomfrom ituseRoom()subscribes to ~15 room store values:activeRoom(),activeMessages(),allRooms(),joinedRooms(),roomsWithUnreadCount(),totalMentionsCount(), etc.ConversationListre-renders per second, triggering the render loop detector and half-freezing the app on LinuxuseRoom()with directroomStore.getState()callbacks — both actions are pure store reads with no reactive subscription needed