diff --git a/src/components/LHNOptionsList/LHNOptionsList.js b/src/components/LHNOptionsList/LHNOptionsList.js index 0d300c5e2179..5e77947187e9 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.js +++ b/src/components/LHNOptionsList/LHNOptionsList.js @@ -1,8 +1,7 @@ -import {FlashList} from '@shopify/flash-list'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback} from 'react'; -import {View} from 'react-native'; +import {FlatList, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import participantPropTypes from '@components/participantPropTypes'; @@ -12,7 +11,6 @@ import compose from '@libs/compose'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; import reportPropTypes from '@pages/reportPropTypes'; -import stylePropTypes from '@styles/stylePropTypes'; import useThemeStyles from '@styles/useThemeStyles'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -21,10 +19,12 @@ import OptionRowLHNData from './OptionRowLHNData'; const propTypes = { /** Wrapper style for the section list */ - style: stylePropTypes, + // eslint-disable-next-line react/forbid-prop-types + style: PropTypes.arrayOf(PropTypes.object), /** Extra styles for the section list container */ - contentContainerStyles: stylePropTypes.isRequired, + // eslint-disable-next-line react/forbid-prop-types + contentContainerStyles: PropTypes.arrayOf(PropTypes.object).isRequired, /** Sections for the section list */ data: PropTypes.arrayOf(PropTypes.string).isRequired, @@ -80,7 +80,7 @@ const defaultProps = { ...withCurrentReportIDDefaultProps, }; -const keyExtractor = (item) => `report_${item}`; +const keyExtractor = (item) => item; function LHNOptionsList({ style, @@ -99,6 +99,28 @@ function LHNOptionsList({ currentReportID, }) { const styles = useThemeStyles(); + /** + * This function is used to compute the layout of any given item in our list. Since we know that each item will have the exact same height, this is a performance optimization + * so that the heights can be determined before the options are rendered. Otherwise, the heights are determined when each option is rendering and it causes a lot of overhead on large + * lists. + * + * @param {Array} itemData - This is the same as the data we pass into the component + * @param {Number} index the current item's index in the set of data + * + * @returns {Object} + */ + const getItemLayout = useCallback( + (itemData, index) => { + const optionHeight = optionMode === CONST.OPTION_MODE.COMPACT ? variables.optionRowHeightCompact : variables.optionRowHeight; + return { + length: optionHeight, + offset: index * optionHeight, + index, + }; + }, + [optionMode], + ); + /** * Function which renders a row in the list * @@ -142,17 +164,20 @@ function LHNOptionsList({ return ( - ); diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index a59dc81aad54..5e69be266342 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -1,7 +1,7 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useRef} from 'react'; -import {InteractionManager, StyleSheet, View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import _ from 'underscore'; import LogoComponent from '@assets/images/expensify-wordmark.svg'; import Header from '@components/Header'; @@ -177,21 +177,16 @@ function SidebarLinks({onLinkClick, insets, optionListItems, isLoading, priority - - - {isLoading && ( - - - - )} - + + + {isLoading && } ); } diff --git a/src/styles/styles.ts b/src/styles/styles.ts index c1b78a224eb3..e597f0ec874e 100644 --- a/src/styles/styles.ts +++ b/src/styles/styles.ts @@ -1367,6 +1367,7 @@ const styles = (theme: ThemeColors) => }, sidebarListContainer: { + scrollbarWidth: 'none', paddingBottom: 4, }, diff --git a/tests/perf-test/SidebarLinks.perf-test.js b/tests/perf-test/SidebarLinks.perf-test.js index 5601c588bb93..f6819d40a48f 100644 --- a/tests/perf-test/SidebarLinks.perf-test.js +++ b/tests/perf-test/SidebarLinks.perf-test.js @@ -105,9 +105,9 @@ test('should scroll and click some of the items', () => { expect(lhnOptionsList).toBeDefined(); fireEvent.scroll(lhnOptionsList, eventData); - // find elements that are currently visible in the viewport - const button1 = await screen.findByTestId('7'); - const button2 = await screen.findByTestId('8'); + + const button1 = await screen.findByTestId('1'); + const button2 = await screen.findByTestId('2'); fireEvent.press(button1); fireEvent.press(button2); };