Skip to content

[Due for payment 2026-07-08][$250] Perf/decompose money request report preview #94603

Description

@mountiny

Problem

MoneyRequestReportPreviewContent (~800 lines, ~55 hook calls) is a single component that bundles five unrelated concerns in one render body — loading-state derivation, the preview-message animation, the header (name / status / expense count), the transaction carousel, and the hold menu. It's mounted once per REPORT_PREVIEW action inside the chat's ReportActionsList, so many instances are live at the same time.

Because everything shares one render and derived state is drilled down through deep prop chains (the action-button + total row alone relayed ~16 props), any state change has a wide blast radius: a single carousel scroll tick or a pay/approve animation frame re-renders the entire card — including the FlashList and every sibling — not just the part that actually changed.

Solution

Decompose MoneyRequestReportPreviewContent into focused, single-responsibility pieces and remove the prop drilling:

  • Extract by concern — useReportPreviewCarousel and usePreviewMessageAnimation hooks; ReportPreviewHeader, TransactionReportCarousel, ReportPreviewTotal, and a gated renderless ReportPreviewHoldMenu; the shell becomes composition only.
  • Remove prop drilling via context — a MoneyRequestReportPreviewProvider owns all the derivations once and exposes them as separate context slices, one per concern: the report data, the loading/UI state, the carousel list, the carousel scroll state, the animation state, the action callbacks, and the refs. Each component reads only the slice(s) it needs, so a change to one slice (e.g. a carousel scroll or a pay/approve animation) doesn't re-render the consumers of another.

PR

#94563

Issue OwnerCurrent Issue Owner: @mallenexpensify
Upwork Automation - Do Not Edit

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2ExternalAdded to denote the issue can be worked on by a contributorOverdue

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions