Skip to content

[Due for payment 2026-09-30] perf: decompose MoneyRequestReportView list components into compiler compliant hooks #99919

Description

@mountiny

Background

MoneyRequestReportView renders the money request report screen with the transactions table and the report actions chat feed. Onyx pushes updates to it continuously (chat messages, transaction changes), and the components derive everything they render: sorting, grouping, violations, columns, selection state.

The view is made of two very large components:

  • MoneyRequestReportActionsList.tsx — 817 lines
  • MoneyRequestReportTransactionList.tsx — 1138 lines

Problem

When a money request report is open, any Onyx update that touches the report (opening it, sending a message, a background sync) makes both list components re-derive and re-render everything. Measured cost: ~1.5s of total re-render time on report open, ~1.0s per message send cycle.

Solution

Decompose both components into small, single purpose hooks and presentational components that the React Compiler can compile and memoize, so each Onyx update re-runs only the derivation chain it affects.

The complete end state is implemented and measured on branch decompose/money-request-report-transaction-list. Land it as ten small, independently mergeable PRs, each a pure refactor with no behavior change.

The tracks are sequential only because Track B reuses Track A's extraction patterns and perf test setup. Pausing between any two PRs leaves main consistent.

Track A: refactor MoneyRequestReportActionsList

  1. PR A0: add performance test. The reassure perf test with Onyx seeding, derived value registration, and the mount + update (send message and unrelated report) scenarios.
  2. PR A1: extract MoneyRequestReportEmptyStateView. Small presentational component (~45 lines). Trims the empty state branch out of the monolith.
  3. PR A2: extract useMoneyRequestReportVisibleActions and adapt useMarkAsRead / useUnreadMarker. Moves the visible actions filtering into a hook and makes the two shared chat hooks consumable from this view.
  4. PR A3: extract useMoneyRequestReportPagination. Older and newer action loading cursors, onStartReached and onEndReached.
  5. PR A4: extract useMoneyRequestReportScroll. Scroll tracking, floating message counter, viewability, and scroll to latest.
  6. PR A5: extract useMoneyRequestReportData.

Track B: refactor MoneyRequestReportTransactionList (after Track A)

  1. PR B1: extract presentational components. MoneyRequestReportGroupByButton, MoneyRequestReportTableHeaderRow, MoneyRequestReportListFooter.
  2. PR B2: extract useMoneyRequestReportColumns and useMoneyRequestReportLayout. Column visibility and sizing, plus the group by layout state.
  3. PR B3: extract the transaction data derivation chain. useMoneyRequestReportSortedTransactions, useMoneyRequestReportGroupedTransactions, useMoneyRequestReportActiveTransactionIDs: sorting, violations, grouping, visual order.
  4. PR B4: extract useMoneyRequestReportTransactionSelection and useMoneyRequestReportPendingExpense, then finish wiring. Selection state, pending expense placeholder, and the final unified list controller shape.

Measured impact (iOS simulator)

Warm report open:

  • ManualOpenReport span: 791ms to 607ms (−23%)
  • Total re-render time: 1517ms to 1239ms (−18%)

Message send:

  • Total re-render time: 1008ms to 743ms (−26%)
  • Track A alone cuts the send and type cycle by ~10.8% (~90ms)
  • ManualSendMessageVisible span: no significant change (743ms vs 706ms, within noise)

References

Issue OwnerCurrent Issue Owner: @suneox

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions