diff --git a/src/components/Search/SearchAutocompleteInput.tsx b/src/components/Search/SearchAutocompleteInput.tsx index 17fbea76e3f8..9ea1aeeeec43 100644 --- a/src/components/Search/SearchAutocompleteInput.tsx +++ b/src/components/Search/SearchAutocompleteInput.tsx @@ -1,6 +1,7 @@ /* eslint-disable rulesdir/no-acc-spread-in-reduce */ +import debounce from 'lodash/debounce'; import type {ForwardedRef, ReactNode, RefObject} from 'react'; -import React, {forwardRef, useCallback, useEffect, useLayoutEffect, useMemo} from 'react'; +import React, {forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useState} from 'react'; import type {StyleProp, TextInputProps, ViewStyle} from 'react-native'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; @@ -131,6 +132,34 @@ function SearchAutocompleteInput( return focusedSharedValue.get() ? wrapperFocusedStyle : wrapperStyle ?? {}; }); + const [internalValue, setInternalValue] = useState(value); + + useEffect(() => { + setInternalValue(value); + }, [value]); + + const debouncedSearchQueryChange = useMemo( + () => + debounce((searchTerm: string) => { + onSearchQueryChange(searchTerm); + }, 300) as ReturnType, + [onSearchQueryChange], + ); + + const handleSearchQueryChange = useCallback( + (searchTerm: string) => { + setInternalValue(searchTerm); + debouncedSearchQueryChange(searchTerm); + }, + [debouncedSearchQueryChange], + ); + + useEffect(() => { + return () => { + debouncedSearchQueryChange.cancel(); + }; + }, [debouncedSearchQueryChange]); + useEffect(() => { runOnLiveMarkdownRuntime(() => { 'worklet'; @@ -190,8 +219,8 @@ function SearchAutocompleteInput( > { setTextInputValue(text); shouldScrollRef.current = true; - setSelection({start: text.length, end: text.length}); + + InteractionManager.runAfterInteractions(() => { + setSelection({start: text.length, end: text.length}); + }); }, [setSelection, setTextInputValue], ); @@ -259,8 +261,8 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla if (item.searchItemType === CONST.SEARCH.SEARCH_ROUTER_ITEM_TYPE.CONTEXTUAL_SUGGESTION) { const searchQuery = getContextualSearchQuery(item); const newSearchQuery = `${searchQuery}\u00A0`; + setTextAndUpdateSelection(newSearchQuery); onSearchQueryChange(newSearchQuery, true); - setSelection({start: newSearchQuery.length, end: newSearchQuery.length}); const autocompleteKey = getContextualSearchAutocompleteKey(item); if (autocompleteKey && item.autocompleteID) { @@ -272,8 +274,8 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla } else if (item.searchItemType === CONST.SEARCH.SEARCH_ROUTER_ITEM_TYPE.AUTOCOMPLETE_SUGGESTION && textInputValue) { const trimmedUserSearchQuery = getQueryWithoutAutocompletedPart(textInputValue); const newSearchQuery = `${trimmedUserSearchQuery}${sanitizeSearchValue(item.searchQuery)}\u00A0`; + setTextAndUpdateSelection(newSearchQuery); onSearchQueryChange(newSearchQuery, true); - setSelection({start: newSearchQuery.length, end: newSearchQuery.length}); if (item.mapKey && item.autocompleteID) { const substitutions = {...autocompleteSubstitutions, [item.mapKey]: item.autocompleteID}; @@ -296,7 +298,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla }); } }, - [autocompleteSubstitutions, onRouterClose, onSearchQueryChange, submitSearch, textInputValue], + [autocompleteSubstitutions, onRouterClose, onSearchQueryChange, submitSearch, textInputValue, setTextAndUpdateSelection], ); const updateAutocompleteSubstitutions = useCallback(