Skip to content

Commit 50270ae

Browse files
authored
Merge pull request Expensify#88714 from callstack-internal/perf/MoneyRequestReportNavigation
Avoid mounting MoneyRequestReportNavigation when unnecessary
2 parents 7e55b29 + 93fc19e commit 50270ae

1 file changed

Lines changed: 77 additions & 17 deletions

File tree

src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,69 @@
11
import React, {useEffect} from 'react';
22
import {View} from 'react-native';
3+
import type {OnyxEntry} from 'react-native-onyx';
34
import PrevNextButtons from '@components/PrevNextButtons';
45
import Text from '@components/Text';
6+
import useOnyx from '@hooks/useOnyx';
57
import useSearchSections from '@hooks/useSearchSections';
68
import useThemeStyles from '@hooks/useThemeStyles';
79
import Navigation from '@navigation/Navigation';
810
import {saveLastSearchParams} from '@userActions/ReportNavigation';
911
import {search} from '@userActions/Search';
1012
import CONST from '@src/CONST';
13+
import ONYXKEYS from '@src/ONYXKEYS';
14+
import type {SearchResults} from '@src/types/onyx';
15+
import type LastSearchParams from '@src/types/onyx/ReportNavigation';
1116

1217
type MoneyRequestReportNavigationProps = {
1318
reportID?: string;
1419
shouldDisplayNarrowVersion: boolean;
1520
};
1621

17-
function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: MoneyRequestReportNavigationProps) {
22+
type SnapshotGuard = {
23+
hasMultiple: boolean;
24+
includesReport: boolean;
25+
};
26+
27+
const EMPTY_GUARD: SnapshotGuard = {hasMultiple: false, includesReport: false};
28+
29+
const selectIsExpenseReportSearch = (lastSearchQuery: OnyxEntry<LastSearchParams>): boolean => lastSearchQuery?.queryJSON?.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT;
30+
31+
const selectQueryHash = (lastSearchQuery: OnyxEntry<LastSearchParams>): number | undefined => lastSearchQuery?.queryJSON?.hash;
32+
33+
const buildSnapshotGuardSelector =
34+
(reportID: string | undefined) =>
35+
(snapshot: OnyxEntry<SearchResults>): SnapshotGuard => {
36+
const data = snapshot?.data;
37+
if (!data || !reportID) {
38+
return EMPTY_GUARD;
39+
}
40+
const prefix = ONYXKEYS.COLLECTION.REPORT;
41+
let count = 0;
42+
let includesReport = false;
43+
for (const key of Object.keys(data)) {
44+
if (!key.startsWith(prefix)) {
45+
continue;
46+
}
47+
count++;
48+
if (!includesReport && key.slice(prefix.length) === reportID) {
49+
includesReport = true;
50+
}
51+
if (count > 1 && includesReport) {
52+
break;
53+
}
54+
}
55+
return {hasMultiple: count > 1, includesReport};
56+
};
57+
58+
function MoneyRequestReportNavigationInner({reportID, shouldDisplayNarrowVersion}: MoneyRequestReportNavigationProps) {
1859
const {allReports, isSearchLoading, lastSearchQuery} = useSearchSections();
60+
const styles = useThemeStyles();
1961

20-
const type = lastSearchQuery?.queryJSON?.type;
2162
const currentIndex = allReports.indexOf(reportID);
2263
const allReportsCount = lastSearchQuery?.previousLengthOfResults ?? 0;
23-
2464
const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1;
2565
const hidePrevButton = currentIndex === 0;
26-
const styles = useThemeStyles();
27-
const isExpenseReportSearch = type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT;
28-
const shouldDisplayNavigationArrows = isExpenseReportSearch && allReports && allReports.length > 1 && currentIndex !== -1 && !!lastSearchQuery?.queryJSON;
66+
const shouldDisplayNavigationArrows = allReports.length > 1 && currentIndex !== -1 && !!lastSearchQuery?.queryJSON;
2967

3068
useEffect(() => {
3169
if (!lastSearchQuery?.queryJSON) {
@@ -100,18 +138,40 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo
100138
goToReportId(allReports.at(prevIndex));
101139
};
102140

141+
if (!shouldDisplayNavigationArrows) {
142+
return null;
143+
}
144+
145+
return (
146+
<View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2]}>
147+
{!shouldDisplayNarrowVersion && <Text style={styles.mutedTextLabel}>{`${currentIndex + 1} of ${allReportsCount}`}</Text>}
148+
<PrevNextButtons
149+
isPrevButtonDisabled={hidePrevButton}
150+
isNextButtonDisabled={hideNextButton}
151+
onNext={goToNextReport}
152+
onPrevious={goToPrevReport}
153+
/>
154+
</View>
155+
);
156+
}
157+
158+
function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: MoneyRequestReportNavigationProps) {
159+
const [isExpenseReportSearch] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {selector: selectIsExpenseReportSearch});
160+
const [hash] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {selector: selectQueryHash});
161+
const snapshotGuardSelector = buildSnapshotGuardSelector(reportID);
162+
const [snapshotGuard = EMPTY_GUARD] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`, {selector: snapshotGuardSelector});
163+
164+
const shouldMount = isExpenseReportSearch && snapshotGuard.hasMultiple && snapshotGuard.includesReport;
165+
166+
if (!shouldMount) {
167+
return null;
168+
}
169+
103170
return (
104-
shouldDisplayNavigationArrows && (
105-
<View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2]}>
106-
{!shouldDisplayNarrowVersion && <Text style={styles.mutedTextLabel}>{`${currentIndex + 1} of ${allReportsCount}`}</Text>}
107-
<PrevNextButtons
108-
isPrevButtonDisabled={hidePrevButton}
109-
isNextButtonDisabled={hideNextButton}
110-
onNext={goToNextReport}
111-
onPrevious={goToPrevReport}
112-
/>
113-
</View>
114-
)
171+
<MoneyRequestReportNavigationInner
172+
reportID={reportID}
173+
shouldDisplayNarrowVersion={shouldDisplayNarrowVersion}
174+
/>
115175
);
116176
}
117177

0 commit comments

Comments
 (0)