Skip to content

Commit 929701d

Browse files
authored
Merge pull request Expensify#66789 from software-mansion-labs/@szymczak/revert-revert-Flatten-transaction-item-row-view-hierarchy-to-improve-performance
Flatten transaction item row view hierarchy to improve performance(fixed after revert)
2 parents e278cef + 813d740 commit 929701d

9 files changed

Lines changed: 167 additions & 145 deletions

File tree

src/components/Search/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,15 +519,18 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
519519
const baseKey = isChat
520520
? `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${(item as ReportActionListItemType).reportActionID}`
521521
: `${ONYXKEYS.COLLECTION.TRANSACTION}${(item as TransactionListItemType).transactionID}`;
522+
522523
// Check if the base key matches the newSearchResultKey (TransactionListItemType)
523524
const isBaseKeyMatch = baseKey === newSearchResultKey;
525+
524526
// Check if any transaction within the transactions array (TransactionGroupListItemType) matches the newSearchResultKey
525527
const isAnyTransactionMatch =
526528
!isChat &&
527529
(item as TransactionGroupListItemType)?.transactions?.some((transaction) => {
528530
const transactionKey = `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`;
529531
return transactionKey === newSearchResultKey;
530532
});
533+
531534
// Determine if either the base key or any transaction key matches
532535
const shouldAnimateInHighlight = isBaseKeyMatch || isAnyTransactionMatch;
533536

src/components/SelectionList/Search/CardListItemHeader.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,14 @@ type CardListItemHeaderProps<TItem extends ListItem> = {
2828
/** Whether this section items disabled for selection */
2929
isDisabled?: boolean | null;
3030

31-
/** Whether the item is hovered */
32-
isHovered?: boolean;
33-
3431
/** Whether the item is focused */
3532
isFocused?: boolean;
3633

3734
/** Whether selecting multiple transactions at once is allowed */
3835
canSelectMultiple: boolean | undefined;
3936
};
4037

41-
function CardListItemHeader<TItem extends ListItem>({card: cardItem, onCheckboxPress, isDisabled, isHovered, isFocused, canSelectMultiple}: CardListItemHeaderProps<TItem>) {
38+
function CardListItemHeader<TItem extends ListItem>({card: cardItem, onCheckboxPress, isDisabled, isFocused, canSelectMultiple}: CardListItemHeaderProps<TItem>) {
4239
const theme = useTheme();
4340
const styles = useThemeStyles();
4441
const StyleUtils = useStyleUtils();
@@ -65,8 +62,7 @@ function CardListItemHeader<TItem extends ListItem>({card: cardItem, onCheckboxP
6562
}, [formattedDisplayName, illustrations, cardItem]);
6663

6764
const backgroundColor =
68-
StyleUtils.getItemBackgroundColorStyle(!!cardItem.isSelected, !!isFocused || !!isHovered, !!isDisabled, theme.activeComponentBG, theme.hoverComponentBG)?.backgroundColor ??
69-
theme.highlightBG;
65+
StyleUtils.getItemBackgroundColorStyle(!!cardItem.isSelected, !!isFocused, !!isDisabled, theme.activeComponentBG, theme.hoverComponentBG)?.backgroundColor ?? theme.highlightBG;
7066

7167
// s77rt add total cell, action cell and collapse/expand button
7268

src/components/SelectionList/Search/ReportListItemHeader.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ type ReportListItemHeaderProps<TItem extends ListItem> = {
3434
/** Whether this section items disabled for selection */
3535
isDisabled?: boolean | null;
3636

37-
/** Whether the item is hovered */
38-
isHovered?: boolean;
39-
4037
/** Whether the item is focused */
4138
isFocused?: boolean;
4239

@@ -162,7 +159,6 @@ function ReportListItemHeader<TItem extends ListItem>({
162159
onSelectRow,
163160
onCheckboxPress,
164161
isDisabled,
165-
isHovered,
166162
isFocused,
167163
canSelectMultiple,
168164
}: ReportListItemHeaderProps<TItem>) {
@@ -175,8 +171,7 @@ function ReportListItemHeader<TItem extends ListItem>({
175171
const showUserInfo = (reportItem.type === CONST.REPORT.TYPE.IOU && thereIsFromAndTo) || (reportItem.type === CONST.REPORT.TYPE.EXPENSE && !!reportItem?.from);
176172

177173
const avatarBorderColor =
178-
StyleUtils.getItemBackgroundColorStyle(!!reportItem.isSelected, !!isFocused || !!isHovered, !!isDisabled, theme.activeComponentBG, theme.hoverComponentBG)?.backgroundColor ??
179-
theme.highlightBG;
174+
StyleUtils.getItemBackgroundColorStyle(!!reportItem.isSelected, !!isFocused, !!isDisabled, theme.activeComponentBG, theme.hoverComponentBG)?.backgroundColor ?? theme.highlightBG;
180175

181176
const handleOnButtonPress = () => {
182177
handleActionButtonPress(currentSearchHash, reportItem, () => onSelectRow(reportItem as unknown as TItem), shouldUseNarrowLayout && !!canSelectMultiple, currentSearchKey);

src/components/SelectionList/Search/TransactionGroupListItem.tsx

Lines changed: 70 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import React, {useMemo} from 'react';
1+
import React, {useCallback, useMemo, useRef} from 'react';
22
import {View} from 'react-native';
33
import type {ValueOf} from 'type-fest';
4+
import {getButtonRole} from '@components/Button/utils';
5+
import OfflineWithFeedback from '@components/OfflineWithFeedback';
6+
import {PressableWithFeedback} from '@components/Pressable';
47
import type {SearchGroupBy} from '@components/Search/types';
5-
import BaseListItem from '@components/SelectionList/BaseListItem';
68
import type {
79
ListItem,
810
TransactionCardGroupListItemType,
@@ -15,8 +17,11 @@ import type {
1517
import Text from '@components/Text';
1618
import TransactionItemRow from '@components/TransactionItemRow';
1719
import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle';
20+
import useHover from '@hooks/useHover';
1821
import useLocalize from '@hooks/useLocalize';
1922
import useResponsiveLayout from '@hooks/useResponsiveLayout';
23+
import useStyleUtils from '@hooks/useStyleUtils';
24+
import useSyncFocus from '@hooks/useSyncFocus';
2025
import useTheme from '@hooks/useTheme';
2126
import useThemeStyles from '@hooks/useThemeStyles';
2227
import {getReportIDForTransaction} from '@libs/MoneyRequestReportUtils';
@@ -71,16 +76,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
7176
backgroundColor: theme.highlightBG,
7277
});
7378

74-
const listItemPressableStyle = [
75-
styles.selectionListPressableItemWrapper,
76-
styles.pv2,
77-
styles.ph0,
78-
styles.overflowHidden,
79-
// Removing background style because they are added to the parent OpacityView via animatedHighlightStyle
80-
styles.bgTransparent,
81-
item.isSelected && styles.activeComponentBG,
82-
styles.mh0,
83-
];
79+
const pressableStyle = [styles.transactionGroupListItemStyle, item.isSelected && styles.activeComponentBG];
8480

8581
const openReportInRHP = (transactionItem: TransactionListItemType) => {
8682
const backTo = Navigation.getActiveRoute();
@@ -112,7 +108,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
112108
COLUMNS.ACTION,
113109
] satisfies Array<ValueOf<typeof COLUMNS>>;
114110

115-
const getHeader = (isHovered: boolean) => {
111+
const getHeader = useMemo(() => {
116112
const headers: Record<SearchGroupBy, React.JSX.Element> = {
117113
[CONST.SEARCH.GROUP_BY.REPORTS]: (
118114
<ReportListItemHeader
@@ -121,7 +117,6 @@ function TransactionGroupListItem<TItem extends ListItem>({
121117
onSelectRow={onSelectRow}
122118
onCheckboxPress={onCheckboxPress}
123119
isDisabled={isDisabledOrEmpty}
124-
isHovered={isHovered}
125120
isFocused={isFocused}
126121
canSelectMultiple={canSelectMultiple}
127122
/>
@@ -139,7 +134,6 @@ function TransactionGroupListItem<TItem extends ListItem>({
139134
card={groupItem as TransactionCardGroupListItemType}
140135
onCheckboxPress={onCheckboxPress}
141136
isDisabled={isDisabledOrEmpty}
142-
isHovered={isHovered}
143137
isFocused={isFocused}
144138
canSelectMultiple={canSelectMultiple}
145139
/>
@@ -151,31 +145,47 @@ function TransactionGroupListItem<TItem extends ListItem>({
151145
}
152146

153147
return headers[groupBy];
154-
};
148+
}, [groupItem, policy, onSelectRow, onCheckboxPress, isDisabledOrEmpty, isFocused, canSelectMultiple, groupBy]);
149+
150+
const StyleUtils = useStyleUtils();
151+
const {hovered, bind} = useHover();
152+
const pressableRef = useRef<View>(null);
153+
154+
const onPress = useCallback(() => {
155+
onSelectRow(item);
156+
}, [item, onSelectRow]);
157+
158+
const onLongPress = useCallback(() => {
159+
onLongPressRow?.(item);
160+
}, [item, onLongPressRow]);
161+
162+
useSyncFocus(pressableRef, !!isFocused, shouldSyncFocus);
155163

156164
return (
157-
<BaseListItem
158-
item={item}
159-
pressableStyle={listItemPressableStyle}
160-
wrapperStyle={[styles.flexRow, styles.flex1, styles.justifyContentBetween, styles.userSelectNone, styles.alignItemsCenter]}
161-
containerStyle={[styles.mb2]}
162-
isFocused={isFocused}
163-
isDisabled={isDisabled}
164-
showTooltip={showTooltip}
165-
canSelectMultiple={canSelectMultiple}
166-
onSelectRow={onSelectRow}
167-
onLongPressRow={onLongPressRow}
168-
pendingAction={item.pendingAction}
169-
keyForList={item.keyForList}
170-
onFocus={onFocus}
171-
shouldShowBlueBorderOnFocus
172-
shouldSyncFocus={shouldSyncFocus}
173-
hoverStyle={item.isSelected && styles.activeComponentBG}
174-
pressableWrapperStyle={[styles.mh5, animatedHighlightStyle]}
175-
>
176-
{(hovered) => (
177-
<View style={[styles.flex1]}>
178-
{getHeader(hovered)}
165+
<OfflineWithFeedback pendingAction={item.pendingAction}>
166+
<PressableWithFeedback
167+
onMouseEnter={bind.onMouseEnter}
168+
onMouseLeave={bind.onMouseLeave}
169+
ref={pressableRef}
170+
onLongPress={onLongPress}
171+
onPress={onPress}
172+
disabled={isDisabled && !item.isSelected}
173+
accessibilityLabel={item.text ?? ''}
174+
role={getButtonRole(true)}
175+
isNested
176+
hoverStyle={[!item.isDisabled && styles.hoveredComponentBG, item.isSelected && styles.activeComponentBG]}
177+
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true, [CONST.INNER_BOX_SHADOW_ELEMENT]: false}}
178+
onMouseDown={(e) => e.preventDefault()}
179+
id={item.keyForList ?? ''}
180+
style={[
181+
pressableStyle,
182+
isFocused && StyleUtils.getItemBackgroundColorStyle(!!item.isSelected, !!isFocused, !!item.isDisabled, theme.activeComponentBG, theme.hoverComponentBG),
183+
]}
184+
onFocus={onFocus}
185+
wrapperStyle={[styles.mb2, styles.mh5, animatedHighlightStyle, styles.userSelectNone]}
186+
>
187+
<View style={styles.flex1}>
188+
{getHeader}
179189
{isEmpty ? (
180190
<View style={[styles.alignItemsCenter, styles.justifyContentCenter, styles.mnh13]}>
181191
<Text
@@ -187,32 +197,31 @@ function TransactionGroupListItem<TItem extends ListItem>({
187197
</View>
188198
) : (
189199
groupItem.transactions.map((transaction) => (
190-
<View key={transaction.transactionID}>
191-
<TransactionItemRow
192-
transactionItem={transaction}
193-
isSelected={!!transaction.isSelected}
194-
dateColumnSize={dateColumnSize}
195-
amountColumnSize={amountColumnSize}
196-
taxAmountColumnSize={taxAmountColumnSize}
197-
shouldShowTooltip={showTooltip}
198-
shouldUseNarrowLayout={!isLargeScreenWidth}
199-
shouldShowCheckbox={!!canSelectMultiple}
200-
onCheckboxPress={() => onCheckboxPress?.(transaction as unknown as TItem)}
201-
columns={columns}
202-
onButtonPress={() => {
203-
openReportInRHP(transaction);
204-
}}
205-
isParentHovered={hovered}
206-
columnWrapperStyles={[styles.ph3, styles.pv1Half]}
207-
isReportItemChild
208-
isInSingleTransactionReport={groupItem.transactions.length === 1}
209-
/>
210-
</View>
200+
<TransactionItemRow
201+
key={transaction.transactionID}
202+
transactionItem={transaction}
203+
isSelected={!!transaction.isSelected}
204+
dateColumnSize={dateColumnSize}
205+
amountColumnSize={amountColumnSize}
206+
taxAmountColumnSize={taxAmountColumnSize}
207+
shouldShowTooltip={showTooltip}
208+
shouldUseNarrowLayout={!isLargeScreenWidth}
209+
shouldShowCheckbox={!!canSelectMultiple}
210+
onCheckboxPress={() => onCheckboxPress?.(transaction as unknown as TItem)}
211+
columns={columns}
212+
onButtonPress={() => {
213+
openReportInRHP(transaction);
214+
}}
215+
isParentHovered={hovered}
216+
columnWrapperStyles={[styles.ph3, styles.pv1Half]}
217+
isReportItemChild
218+
isInSingleTransactionReport={groupItem.transactions.length === 1}
219+
/>
211220
))
212221
)}
213222
</View>
214-
)}
215-
</BaseListItem>
223+
</PressableWithFeedback>
224+
</OfflineWithFeedback>
216225
);
217226
}
218227

0 commit comments

Comments
 (0)