diff --git a/.changeset/message-list-history-loop-while-hidden.md b/.changeset/message-list-history-loop-while-hidden.md new file mode 100644 index 0000000000000..c2c72007aacf7 --- /dev/null +++ b/.changeset/message-list-history-loop-while-hidden.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed the message list loading the entire room history while it is hidden behind a full-width contextual bar. On a narrow window the room layout hides the message body, and a hidden element reports its height and scroll offset as `0`, which made the load-older-messages check always true - so every page that arrived triggered the next one until the whole room was in memory, hammering the server until it rate-limited the client. On returning to the list the scroll position was far in the past, because the content had grown underneath it. diff --git a/apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx b/apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx index 1a388da54b55b..82279a342927c 100644 --- a/apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx +++ b/apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx @@ -66,6 +66,40 @@ describe('useGetMore', () => { }); }); + it('should not call getMore while the list is hidden, even though it reports being at the top', async () => { + const root = mockAppRoot(); + (RoomHistoryManager.isLoading as jest.Mock).mockReturnValue(false); + (RoomHistoryManager.hasMore as jest.Mock).mockReturnValue(true); + (RoomHistoryManager.hasMoreNext as jest.Mock).mockReturnValue(false); + (RoomHistoryManager.getMore as jest.Mock).mockClear(); + + const Test = () => { + const [atBottom] = useState(false); + const { innerRef } = useGetMore('room-id', atBottom); + return
; + }; + + // What a display: none element reports. Without a guard `scrollTop <= clientHeight / 3` is + // 0 <= 0, so every observer callback would load another page of history. + (getBoundingClientRect as jest.Mock).mockReturnValue({ + scrollTop: 0, + clientHeight: 0, + scrollHeight: 0, + }); + + render(