perf: Split TransactionItemRow into narrow and wide versions#89120
perf: Split TransactionItemRow into narrow and wide versions#89120jmusial wants to merge 5 commits intoExpensify:mainfrom
Conversation
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d8ee4fda6
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| taxAmountColumnSize={CONST.SEARCH.TABLE_COLUMN_SIZES.NORMAL} | ||
| shouldShowCheckbox={!!canSelectMultiple} | ||
| checkboxSentryLabel={CONST.SENTRY_LABEL.SEARCH.TRANSACTION_LIST_ITEM_CHECKBOX} | ||
| style={[styles.p3, styles.pv2, shouldUseNarrowLayout ? [styles.p0, styles.pt3] : [styles.noBorderRadius]]} |
There was a problem hiding this comment.
Keep narrow transaction rows square-cornered
The narrow list path no longer includes styles.noBorderRadius when rendering TransactionItemRow, but TransactionItemRowNarrow still applies styles.expenseWidgetRadius internally. On small screens this reintroduces rounded inner corners in hydrated search rows, while the static placeholder list still uses square corners, causing a visible shape jump when the real list replaces the static one and breaking the stated narrow-layout visual parity.
Useful? React with 👍 / 👎.
| isDescription={!merchant} | ||
| /> | ||
| ) : null} | ||
| <View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2]}> |
There was a problem hiding this comment.
Right-align amount block when merchant text is absent
The trailing amount/comments container is always rendered without the previous conditional mlAuto, so when merchantOrDescription is empty the row has only one child in this justifyContentBetween section and it sits at the left instead of the right. This misaligns amount/comment content for transactions without merchant/description (common for partial scans or missing fields).
Useful? React with 👍 / 👎.
|
@ChavdaSachin Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
I'll be OOO until 10 May. @OlGierd03 will be looking after this PR until then. |
|
|
||
| // eslint-disable-next-line react/jsx-props-no-spreading | ||
| return <ChatBubbleCell {...props} />; | ||
| } |
There was a problem hiding this comment.
❌ CONSISTENCY-5 (docs)
The eslint-disable-next-line react/jsx-props-no-spreading lacks a comment explaining why the rule is disabled.
Add a justification comment:
// Deferred wrapper intentionally forwards all props to the underlying component
// eslint-disable-next-line react/jsx-props-no-spreading
return <ChatBubbleCell {...props} />;Reviewed at: 7d8ee4f | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.
| } | ||
|
|
||
| // eslint-disable-next-line react/jsx-props-no-spreading | ||
| return <TransactionItemRowRBR {...props} />; |
There was a problem hiding this comment.
❌ CONSISTENCY-5 (docs)
The eslint-disable-next-line react/jsx-props-no-spreading lacks a comment explaining why the rule is disabled.
Add a justification comment:
// Deferred wrapper intentionally forwards all props to the underlying component
// eslint-disable-next-line react/jsx-props-no-spreading
return <TransactionItemRowRBR {...props} />;Reviewed at: 7d8ee4f | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.
| import DeferredTransactionItemRowRBR from './DeferredTransactionItemRowRBR'; | ||
| import type {TransactionItemRowNarrowComputedData, TransactionItemRowProps} from './types'; | ||
|
|
||
| type TransactionItemRowNarrowProps = Omit<TransactionItemRowProps, 'shouldUseNarrowLayout' | 'policyForMovingExpenses'> & TransactionItemRowNarrowComputedData; |
There was a problem hiding this comment.
❌ CONSISTENCY-4 (docs)
TransactionItemRowNarrowProps is defined as Omit<TransactionItemRowProps, 'shouldUseNarrowLayout' | 'policyForMovingExpenses'> & TransactionItemRowNarrowComputedData, which pulls in many wide-layout-only props that the narrow component never destructures or uses: dateColumnSize, submittedColumnSize, approvedColumnSize, postedColumnSize, exportedColumnSize, amountColumnSize, taxAmountColumnSize, isReportItemChild, isActionColumnWide, isHover, isLargeScreenWidth, onButtonPress, isActionLoading, shouldHighlightItemWhenSelected, columns, reportActions, nonPersonalAndWorkspaceCards, and policy.
Define a narrow-specific props type using Pick that only includes props the component actually uses:
type TransactionItemRowNarrowProps = Pick<TransactionItemRowProps,
'transactionItem' | 'report' | 'isSelected' | 'shouldShowTooltip' |
'onCheckboxPress' | 'shouldShowCheckbox' | 'style' |
'isInSingleTransactionReport' | 'shouldShowRadioButton' |
'onRadioButtonPress' | 'shouldShowErrors' | 'isDisabled' |
'violations' | 'shouldShowBottomBorder' | 'onArrowRightPress' |
'shouldShowArrowRightOnNarrowLayout' | 'checkboxSentryLabel'
> & TransactionItemRowNarrowComputedData;This also means the parent dispatcher should construct narrow-only props instead of spreading all sharedProps.
Reviewed at: 7d8ee4f | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.
|
@OlGierd03, please take a look at the AI review comments and let me know when the PR is ready for the review. |
|
Sure thing, I'll get around to it soon |
Explanation of Change
Split
TransactionItemRow(the inner data-row) andTransactionListItem(the outer search-list item) into viewport-specific variants — *Wide (table layout) and *Narrow (mobile layout) — so each viewport only loads the code, column renderers, and dependencies it actually needs.Also introduced three deferred-rendering wrappers.
DeferredActionCell— renders a pulsing skeleton on first paint, then swaps in the real ActionCell after a transitionDeferredChatBubbleCell— same pattern for the comment-count bubble iconDeferredTransactionItemRowRBR— defers the RBR (red-brick-road) violation/error rowThis keeps large search result lists responsive on initial render by letting React paint the visible shell immediately and hydrate heavier sub-trees in a lower-priority pass.
Note: this PR overlaps with #89083
Perf gains
Fixed Issues
$ #89123
PROPOSAL:
Tests
Offline tests
Same as tests.
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
MacOS: Chrome / Safari
Screen.Recording.2026-04-29.at.15.56.23.mov