From 590482a4c5103ad4b104ef550dff803b349f4917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Mon, 4 May 2026 10:14:51 +0200 Subject: [PATCH] fix(perf): stop ConversationList from subscribing to all room state 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. --- .../sidebar-components/ConversationList.tsx | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/fluux/src/components/sidebar-components/ConversationList.tsx b/apps/fluux/src/components/sidebar-components/ConversationList.tsx index c5427dd7..8d66fbf3 100644 --- a/apps/fluux/src/components/sidebar-components/ConversationList.tsx +++ b/apps/fluux/src/components/sidebar-components/ConversationList.tsx @@ -1,12 +1,12 @@ -import React, { useState, useRef, memo } from 'react' +import React, { useState, useRef, memo, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { useListKeyboardNav, useRouteSync } from '@/hooks' import { detectRenderLoop, trackSelectorChange } from '@/utils/renderLoopDetector' import { useChat, useRoster, - useRoom, chatStore, + roomStore, generateConsistentColorHexSync, formatMessagePreview, type Conversation, @@ -46,7 +46,19 @@ export function ConversationList() { deleteConversation, archiveConversation, } = useChat() - const { setActiveRoom, getRoom } = useRoom() + // Direct store access — avoids subscribing to all room state (activeRoom, activeMessages, + // allRooms, roomsWithUnreadCount, etc.) that useRoom() would pull in. During sync, + // rapid room updates would cause 500+ renders/second through useRoom(). + const setActiveRoom = useCallback(async (roomJid: string | null) => { + if (roomJid) { + await roomStore.getState().loadMessagesFromCache(roomJid, { limit: 100 }) + } + roomStore.getState().setActiveRoom(roomJid) + }, []) + const getRoom = useCallback( + (roomJid: string) => roomStore.getState().rooms.get(roomJid), + [] + ) const { contacts } = useRoster() const { navigateToMessages } = useRouteSync() const listRef = useRef(null) @@ -130,7 +142,16 @@ export function ArchiveList() { deleteConversation, unarchiveConversation, } = useChat() - const { setActiveRoom, getRoom } = useRoom() + const setActiveRoom = useCallback(async (roomJid: string | null) => { + if (roomJid) { + await roomStore.getState().loadMessagesFromCache(roomJid, { limit: 100 }) + } + roomStore.getState().setActiveRoom(roomJid) + }, []) + const getRoom = useCallback( + (roomJid: string) => roomStore.getState().rooms.get(roomJid), + [] + ) const { contacts } = useRoster() const { navigateToArchive } = useRouteSync() const listRef = useRef(null)