Skip to content

perf: Use useInfiniteQuery to prevent UI freeze in message tabs#40353

Open
TasfinMahmud wants to merge 1 commit intoRocketChat:developfrom
TasfinMahmud:fix/infinite-query-mentions-starred
Open

perf: Use useInfiniteQuery to prevent UI freeze in message tabs#40353
TasfinMahmud wants to merge 1 commit intoRocketChat:developfrom
TasfinMahmud:fix/infinite-query-mentions-starred

Conversation

@TasfinMahmud
Copy link
Copy Markdown

@TasfinMahmud TasfinMahmud commented Apr 30, 2026

Fixes #39237

Summary

Replaces the blocking sequential for-loop fetching pattern in both MentionsTab and StarredMessagesTab with useInfiniteQuery from TanStack Query, enabling page-by-page data loading triggered by user scroll.

Problem

Both MentionsTab.tsx and StarredMessagesTab.tsx used a for loop inside useQuery to fetch all pages sequentially before rendering:

for (let offset = 0, result = await getMessages({ roomId, offset: 0 }); result.count > 0; ...) {
  messages.push(...result.messages);
}

This caused a blocking UI state - users couldn't see any results until every single page was loaded from the server.

Solution

  • MentionsTab.tsx: Migrated from useQuery -> useInfiniteQuery with getNextPageParam for cursor-based pagination
    • StarredMessagesTab.tsx: Same migration, preserving onClientMessageReceived processing
    • MessageListTab.tsx: Updated props interface to accept messages[], isLoading, isSuccess, isFetchingNextPage, and onEndReached instead of UseQueryResult<IMessage[]>. Added Virtuoso's endReached callback for scroll-triggered loading and a bottom <Throbber> for next-page loading state.

Behavior Change

Before After
All pages fetched sequentially before any render First page renders immediately
UI blocked during full data load Smooth infinite scroll as user reaches bottom
Single useQuery with blocking loop useInfiniteQuery with getNextPageParam

Testing

  • Verified TypeScript compilation passes
    • Manually tested mentions and starred messages panels with varying message counts

Summary by CodeRabbit

  • Performance Improvements

    • Mentions, starred and pinned sections now load progressively page-by-page as you scroll, improving initial load and responsiveness for large conversations.
  • New Features

    • Infinite scrolling with automatic fetching of additional pages when reaching the end.
    • Message lists now receive explicit message and loading states plus an on-end-reached handler for clearer pagination control.
  • Bug Fixes

    • More reliable empty/content/loading states and a separate next-page loading indicator during incremental loads.

@TasfinMahmud TasfinMahmud requested a review from a team as a code owner April 30, 2026 21:29
@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot Bot commented Apr 30, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project
  • This PR has an invalid title

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 30, 2026

⚠️ No Changeset found

Latest commit: 341966e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 30, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Walkthrough

Replaces eager, sequential pagination in Mentions, Starred, and Pinned message tabs with paginated streaming via useInfiniteQuery; MessageListTab now receives explicit messages and loading/pagination flags plus an onEndReached callback to load additional pages.

Changes

Cohort / File(s) Summary
Infinite Query Pagination
apps/meteor/client/views/room/contextualBar/MentionsTab.tsx, apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx, apps/meteor/client/views/room/contextualBar/PinnedMessagesTab.tsx
Replaced looped useQuery that eagerly fetched all pages with useInfiniteQuery using a fixed page COUNT. Each component now returns page-shaped data (messages, total, count, offset), flattens data.pages into a memoized messages array, computes getNextPageParam, and provides onEndReached that conditionally calls fetchNextPage().
Pagination Props Consumer
apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
Removed queryResult: UseQueryResult<IMessage[]>; added props messages: IMessage[], isLoading, isSuccess, optional isFetchingNextPage?, and onEndReached?. Updated rendering gates, Virtuoso data/totalCount to use messages, forwarded end-of-list events to onEndReached, and render a next-page loading indicator when isFetchingNextPage.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Tab as Mentions/Starred/Pinned Tab
    participant Query as useInfiniteQuery
    participant Server
    participant List as MessageListTab/Virtuoso

    User->>Tab: Mount
    Tab->>Query: fetch page (pageParam=offset=0, count=COUNT)
    Query->>Server: GET /api/messages?offset=0&count=COUNT
    Server-->>Query: return { messages, total, count, offset }
    Query-->>Tab: page data
    Tab->>Tab: map & flatten pages → messages
    Tab-->>List: render messages + onEndReached
    User->>List: scroll to bottom
    List->>Tab: onEndReached()
    alt hasNextPage && !isFetchingNextPage
        Tab->>Query: fetchNextPage()
        Query->>Server: GET /api/messages?offset=nextOffset&count=COUNT
        Server-->>Query: return next page
        Query-->>Tab: page data
        Tab->>List: render appended messages + isFetchingNextPage indicator
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

type: bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning PinnedMessagesTab.tsx was also migrated to useInfiniteQuery despite not being mentioned in the PR title or linked issue #39237. Either include PinnedMessagesTab changes in the PR title, update the linked issue, or extract PinnedMessagesTab changes into a separate PR to maintain focus on issue #39237.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed All core objectives from issue #39237 are met: blocking sequential loops replaced with useInfiniteQuery, enabling page-by-page loading on scroll.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly summarizes the main change: migrating to useInfiniteQuery to improve performance by preventing UI freezes during message loading.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@TasfinMahmud TasfinMahmud changed the title perf: refactor MentionsTab and StarredMessagesTab to use useInfiniteQuery fix: refactor MentionsTab and StarredMessagesTab to use useInfiniteQuery Apr 30, 2026
@coderabbitai coderabbitai Bot added the type: feature Pull requests that introduces new feature label Apr 30, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/meteor/client/views/room/contextualBar/MessageListTab.tsx (1)

29-39: ⚠️ Potential issue | 🟠 Major

Migrate PinnedMessagesTab to updated MessageListTab prop contract.

The prop contract change from queryResult to explicit props (messages, isLoading, isSuccess, isFetchingNextPage, onEndReached) in MessageListTab requires migrating all callers. StarredMessagesTab and MentionsTab have been migrated, but PinnedMessagesTab still passes queryResult={pinnedMessagesQueryResult} at line 43, which will cause a type error. Update PinnedMessagesTab to extract and pass individual props matching the new signature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/views/room/contextualBar/MessageListTab.tsx` around lines
29 - 39, PinnedMessagesTab is still passing the old queryResult prop
(pinnedMessagesQueryResult) to MessageListTab; update PinnedMessagesTab to
unpack the needed fields from pinnedMessagesQueryResult and pass them
individually to MessageListTab: extract messages, isLoading, isSuccess,
isFetchingNextPage, and onEndReached (or a noop) from pinnedMessagesQueryResult
and supply those props along with existing iconName/title/emptyResultMessage so
the call matches MessageListTab's new prop contract (MessageListTab,
pinnedMessagesQueryResult, PinnedMessagesTab).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/client/views/room/contextualBar/MentionsTab.tsx`:
- Around line 45-49: Update the guard in handleEndReached to prevent starting a
pagination fetch while any fetch is in progress: replace the check against
mentionedMessagesQueryResult.isFetchingNextPage with
mentionedMessagesQueryResult.isFetching so the condition becomes "hasNextPage &&
!isFetching" before calling mentionedMessagesQueryResult.fetchNextPage(); keep
the rest of the callback and dependency on mentionedMessagesQueryResult
unchanged.

In `@apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx`:
- Around line 46-50: The guard in handleEndReached currently checks
starredMessagesQueryResult.hasNextPage &&
!starredMessagesQueryResult.isFetchingNextPage which can allow concurrent
fetches during background refetches; change the condition to
starredMessagesQueryResult.hasNextPage && !starredMessagesQueryResult.isFetching
so fetchNextPage() is only called when no fetch (including background refetch)
is active—update the check inside the handleEndReached callback to use
isFetching and keep the call to starredMessagesQueryResult.fetchNextPage()
otherwise unchanged.

---

Outside diff comments:
In `@apps/meteor/client/views/room/contextualBar/MessageListTab.tsx`:
- Around line 29-39: PinnedMessagesTab is still passing the old queryResult prop
(pinnedMessagesQueryResult) to MessageListTab; update PinnedMessagesTab to
unpack the needed fields from pinnedMessagesQueryResult and pass them
individually to MessageListTab: extract messages, isLoading, isSuccess,
isFetchingNextPage, and onEndReached (or a noop) from pinnedMessagesQueryResult
and supply those props along with existing iconName/title/emptyResultMessage so
the call matches MessageListTab's new prop contract (MessageListTab,
pinnedMessagesQueryResult, PinnedMessagesTab).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ccb99ae1-3291-4041-a754-605fe41a4e4c

📥 Commits

Reviewing files that changed from the base of the PR and between 981af32 and a50bcf1.

📒 Files selected for processing (3)
  • apps/meteor/client/views/room/contextualBar/MentionsTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MentionsTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
🧠 Learnings (13)
📚 Learning: 2026-03-11T22:04:20.529Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 39545
File: apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts:59-61
Timestamp: 2026-03-11T22:04:20.529Z
Learning: In `apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts`, the `msg.u._id === uid` early-return in the `streamNewMessage` handler is intentional: the "New messages" indicator is designed to notify about messages from other users only. Self-sent messages — including those sent from a different session/device — are always skipped, by design. Do not flag this as a multi-session regression.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MentionsTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-04-29T20:06:34.862Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 40268
File: apps/meteor/client/startup/incomingMessages.ts:21-25
Timestamp: 2026-04-29T20:06:34.862Z
Learning: In `apps/meteor/client/startup/incomingMessages.ts`, the `Messages.state.update` predicate that strips `ignored` from records when `'ignored' in sub` is false (i.e., the subscription update has no `ignored` field) is intentional. Absence of `ignored` in a `subscriptions-changed` event means the user's ignore list is empty/reset, so clearing all existing `ignored` flags on messages for that room is the correct behavior. Do not flag this as an unintentional ignored-state reset on unrelated subscription updates.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-04-28T14:08:46.920Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 40105
File: apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts:54-67
Timestamp: 2026-04-28T14:08:46.920Z
Learning: In `apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts`, setting `isJumpingToMessage.current = true` before the guard clauses (RoomHistoryManager.isLoading check, message not found check) is intentional. The flag means "a jump is pending/in progress" and must stay `true` through all intermediate early-return paths (loading, unresolved message, etc.) so that downstream scroll and load behavior is suppressed while waiting for the jump conditions to be satisfied. Do not flag this as a "flag stuck true" bug.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-02-24T19:36:55.089Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/page-objects/fragments/home-content.ts:60-82
Timestamp: 2026-02-24T19:36:55.089Z
Learning: In RocketChat/Rocket.Chat e2e tests (apps/meteor/tests/e2e/page-objects/fragments/home-content.ts), thread message preview listitems do not have aria-roledescription="message", so lastThreadMessagePreview locator cannot be scoped to messageListItems (which filters for aria-roledescription="message"). It should remain scoped to page.getByRole('listitem') or mainMessageList.getByRole('listitem').

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-04-18T12:32:53.425Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 38623
File: apps/meteor/app/lib/server/functions/cleanRoomHistory.ts:146-149
Timestamp: 2026-04-18T12:32:53.425Z
Learning: In `apps/meteor/app/lib/server/functions/cleanRoomHistory.ts` (PR `#38623`), the read-receipt cleanup (both `ReadReceipts.removeByMessageIds` and `ReadReceiptsArchive.removeByMessageIds`) is intentionally only performed in the limited prune path (`limit && selectedMessageIds`). The unlimited/delete-all path (`limit === 0`) deliberately skips cleaning up orphaned read receipts in both hot and cold storage — this is by design. Do not flag this as a bug or missing cleanup in future reviews.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
📚 Learning: 2025-12-02T22:23:49.593Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37654
File: apps/meteor/client/hooks/useAppSlashCommands.ts:32-38
Timestamp: 2025-12-02T22:23:49.593Z
Learning: In apps/meteor/client/hooks/useAppSlashCommands.ts, the `data?.forEach((command) => slashCommands.add(command))` call during render is intentional. The query is configured with `structuralSharing: false` to prevent React Query from keeping stable data references, and `slashCommands.add` is idempotent, so executing on every render is acceptable and ensures the command registry stays current.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-04-13T16:40:55.864Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 40100
File: apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx:18-35
Timestamp: 2026-04-13T16:40:55.864Z
Learning: In Rocket.Chat's embedded mode (`?layout=embedded`), route changes are driven by the parent frame reloading the iframe URL, which causes a full remount of the React tree (including `EmbeddedPreload` at `apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx`). The component never survives a navigation, so `roomParams` (computed via `useMemo`) is always fresh on mount. A `[router]` singleton as the sole `useMemo` dependency is therefore correct and intentional — do not flag it as a stale-dependency bug in this component.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MentionsTab.tsx
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-03-11T18:17:53.972Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/processMessageUploads.ts:112-119
Timestamp: 2026-03-11T18:17:53.972Z
Learning: In `apps/meteor/client/lib/chats/flows/processMessageUploads.ts`, when sending multiple file uploads, each file is confirmed via its own `/rooms.mediaConfirm/${rid}/${fileId}` call and produces a separate message. Only the first file's confirm payload carries the composed message text (`msg`); all subsequent files receive `msg: ''`. This one-message-per-file behavior is intentional by design — do not flag it as a bug or suggest batching into a single message.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
📚 Learning: 2026-02-24T19:09:09.561Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
  • apps/meteor/client/views/room/contextualBar/MentionsTab.tsx
  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-03-12T10:26:26.697Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39340
File: apps/meteor/app/api/server/v1/im.ts:1349-1398
Timestamp: 2026-03-12T10:26:26.697Z
Learning: In `apps/meteor/app/api/server/v1/im.ts` (PR `#39340`), the `DmEndpoints` type intentionally includes temporary stub entries for `/v1/im.kick`, `/v1/dm.kick`, `/v1/im.leave`, and `/v1/dm.leave` (using `DmKickProps` and `DmLeaveProps`) even though no route handlers exist for them yet. These stubs were added to preserve type compatibility after removing the original `DmLeaveProps` and related files. They are planned for cleanup in a follow-up PR. Do not flag these as missing implementations when reviewing this file until the follow-up is merged.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx
📚 Learning: 2026-04-17T17:38:15.994Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 39858
File: packages/ui-kit/src/interactions/UserInteraction.ts:33-33
Timestamp: 2026-04-17T17:38:15.994Z
Learning: In RocketChat/Rocket.Chat (`packages/ui-kit/src/interactions/UserInteraction.ts`), `ViewSubmitUserInteraction` and `ViewClosedUserInteraction` intentionally do NOT include `rid` when the interaction originates from a **modal** surface. Modals are not scoped to a room, so no room id is available in that context. The `rid?: string` field is optional to support the contextual bar surface (where room context exists) while remaining absent for modals. Do not flag the absence of `rid` in modal viewSubmit/viewClosed interactions as a missing-context bug.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/MessageListTab.tsx

Comment thread apps/meteor/client/views/room/contextualBar/MentionsTab.tsx
Comment thread apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx
@coderabbitai coderabbitai Bot added type: bug and removed type: feature Pull requests that introduces new feature labels Apr 30, 2026
TasfinMahmud added a commit to TasfinMahmud/Rocket.Chat that referenced this pull request Apr 30, 2026
…bbit review

- Migrate PinnedMessagesTab from useQuery with blocking for-loop to useInfiniteQuery

- Use isFetching instead of isFetchingNextPage in all handleEndReached guards to prevent concurrent fetches during background refetches

- Addresses CodeRabbit review comments on PR RocketChat#40353
@coderabbitai coderabbitai Bot removed the type: bug label Apr 30, 2026
…to use useInfiniteQuery

Replaces blocking sequential for-loop fetching with useInfiniteQuery for MentionsTab, StarredMessagesTab, and PinnedMessagesTab components.

Before: All pages were fetched sequentially in a for loop inside useQuery, blocking the UI until every page was loaded.

After: Only the first page is fetched initially. Additional pages are loaded on-demand as the user scrolls to the bottom of the list using Virtuoso's endReached callback.

Changes:

- MentionsTab: useQuery -> useInfiniteQuery with page-by-page fetching

- StarredMessagesTab: useQuery -> useInfiniteQuery with page-by-page fetching

- PinnedMessagesTab: useQuery -> useInfiniteQuery with page-by-page fetching

- MessageListTab: Accept individual props instead of UseQueryResult, add endReached prop to Virtuoso, show loading indicator for next page

- Use isFetching guard in handleEndReached to prevent concurrent fetches

Fixes RocketChat#39237
@TasfinMahmud TasfinMahmud force-pushed the fix/infinite-query-mentions-starred branch from 3836982 to 341966e Compare April 30, 2026 21:51
@TasfinMahmud TasfinMahmud changed the title fix: refactor MentionsTab and StarredMessagesTab to use useInfiniteQuery fix: refactor MentionsTab, StarredMessagesTab, and PinnedMessagesTab to use useInfiniteQuery Apr 30, 2026
@TasfinMahmud TasfinMahmud changed the title fix: refactor MentionsTab, StarredMessagesTab, and PinnedMessagesTab to use useInfiniteQuery perf: Use useInfiniteQuery to prevent UI freeze in message tabs May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PERFORMANCE: Starred Messages/Mentions tabs perform blocking sequential waterfalls

2 participants