From f7ca4014a94388804331d4fcdf2ae98b39b20c18 Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Tue, 27 Feb 2024 19:56:32 +0100 Subject: [PATCH 1/3] Recalculate the sections only on actual change --- src/components/OptionsSelector/BaseOptionsSelector.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index 23451b8e1a09..d8ed45f5d6eb 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -1,5 +1,6 @@ import {useIsFocused} from '@react-navigation/native'; import lodashGet from 'lodash/get'; +import lodashIsEqual from 'lodash/isEqual'; import PropTypes from 'prop-types'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {ScrollView, View} from 'react-native'; @@ -14,6 +15,7 @@ import ShowMoreButton from '@components/ShowMoreButton'; import TextInput from '@components/TextInput'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useLocalize from '@hooks/useLocalize'; +import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlatform from '@libs/getPlatform'; import KeyboardShortcut from '@libs/KeyboardShortcut'; @@ -100,6 +102,7 @@ function BaseOptionsSelector(props) { const prevPaginationPage = useRef(paginationPage); const prevSelectedOptions = useRef(props.selectedOptions); const prevValue = useRef(value); + const previousSections = usePrevious(props.sections); useImperativeHandle(props.forwardedRef, () => textInputRef.current); @@ -143,7 +146,7 @@ function BaseOptionsSelector(props) { /** * Maps sections to render only allowed count of them per section. * - * @returns {Objects[]} + * @returns {Object[]} */ const sliceSections = useCallback( () => @@ -415,6 +418,10 @@ function BaseOptionsSelector(props) { }, [isFocused, props.autoFocus]); useEffect(() => { + if (lodashIsEqual(props.sections, previousSections)) { + return; + } + const newSections = sliceSections(); const newOptions = flattenSections(); @@ -434,7 +441,7 @@ function BaseOptionsSelector(props) { setFocusedIndex(prevFocusedOptionIndex || (_.isNumber(props.focusedIndex) ? props.focusedIndex : newFocusedIndex)); // we want to run this effect only when the sections change // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.sections]); + }, [props.sections, previousSections]); useEffect(() => { // If we just toggled an option on a multi-selection page or cleared the search input, scroll to top From 8e816ff76502b7a412d53f804f17e18c6293e2da Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Tue, 27 Feb 2024 20:53:23 +0100 Subject: [PATCH 2/3] Set sections to initial value on render --- src/components/OptionsSelector/BaseOptionsSelector.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index d8ed45f5d6eb..ac76846ab2e3 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -346,6 +346,9 @@ function BaseOptionsSelector(props) { [allOptions, sections], ); + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => setSections(sliceSections()), []); + useEffect(() => { subscribeToEnterShortcut(); subscribeToCtrlEnterShortcut(); From b39957f599bc7d9807ae7a843ac10f1caf472f1e Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Tue, 27 Feb 2024 21:37:25 +0100 Subject: [PATCH 3/3] Initialize sections with a value --- .../OptionsSelector/BaseOptionsSelector.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index ac76846ab2e3..1fa63f181dd6 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -85,7 +85,6 @@ function BaseOptionsSelector(props) { const accessibilityRoles = _.values(CONST.ROLE); const [disabledOptionsIndexes, setDisabledOptionsIndexes] = useState([]); - const [sections, setSections] = useState(); const [shouldDisableRowSelection, setShouldDisableRowSelection] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const [value, setValue] = useState(''); @@ -137,12 +136,6 @@ function BaseOptionsSelector(props) { return calcAllOptions; }, [props.sections]); - // eslint-disable-next-line react-hooks/exhaustive-deps - const initialAllOptions = useMemo(() => flattenSections(), []); - const [allOptions, setAllOptions] = useState(initialAllOptions); - const [focusedIndex, setFocusedIndex] = useState(getInitiallyFocusedIndex(initialAllOptions)); - const [focusedOption, setFocusedOption] = useState(allOptions[focusedIndex]); - /** * Maps sections to render only allowed count of them per section. * @@ -165,6 +158,13 @@ function BaseOptionsSelector(props) { [paginationPage, props.sections], ); + // eslint-disable-next-line react-hooks/exhaustive-deps + const initialAllOptions = useMemo(() => flattenSections(), []); + const [sections, setSections] = useState(sliceSections()); + const [allOptions, setAllOptions] = useState(initialAllOptions); + const [focusedIndex, setFocusedIndex] = useState(getInitiallyFocusedIndex(initialAllOptions)); + const [focusedOption, setFocusedOption] = useState(allOptions[focusedIndex]); + /** * Completes the follow-up actions after a row is selected * @@ -346,9 +346,6 @@ function BaseOptionsSelector(props) { [allOptions, sections], ); - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(() => setSections(sliceSections()), []); - useEffect(() => { subscribeToEnterShortcut(); subscribeToCtrlEnterShortcut();