import { useEffect , useRef , useState } from 'react' ; import { cancellablePromise } from '../../utils/cancellablePromise' ; import { useDebouncedEffect } from '../../hooks/useDebouncedEffect' ; export type GetSuggestionsFunction < SuggestionItemType > = ( searchString : string ) => Promise < SuggestionItemType [ ] > ; export const SUGGESTIONS_DEBOUNCE_VALUE = 200 ; export const useSuggestions = < SuggestionItemType > ( searchString , getSuggestions , isSubmitted ) => { const cancelAll = useRef ( isSubmitted ) ; const [ isLoading , setIsLoading ] = useState ( false ) ; const cancelSuggestionsFunction = useRef < Function > ( ( ) => null ) ; const [ suggestions , setSuggestions ] = useState < SuggestionItemType [ ] > ( [ ] ) ; useEffect ( ( ) => { cancelAll . current = isSubmitted ; } , [ isSubmitted ] ) ; useDebouncedEffect ( ( ) => { if ( typeof getSuggestions !== 'function' || cancelAll . current === true ) { return ; } setIsLoading ( true ) ; cancelSuggestionsFunction . current ( ) ; if ( searchString . length === 0 ) { setIsLoading ( false ) ; setSuggestions ( [ ] ) ; return ; } const { promise , cancel } = cancellablePromise < SuggestionItemType [ ] > ( getSuggestions ( searchString ) ) ; cancelSuggestionsFunction . current = cancel ; promise . then ( ( newSuggestions ) => { setIsLoading ( false ) ; if ( Array . isArray ( newSuggestions ) && typeof setSuggestions === 'function' && cancelAll . current === false ) { setSuggestions ( newSuggestions ) ; } } ) ; } , SUGGESTIONS_DEBOUNCE_VALUE , [ searchString , getSuggestions , setSuggestions ] ) ; return { suggestions , isLoading : cancelAll . current ? false : isLoading } ; } ;