UNPKG

@gravityforms/components

Version:

UI components for use in Gravity Forms development. Both React and vanilla js flavors.

117 lines (106 loc) 3.14 kB
import { React } from '@gravityforms/libraries'; import { debounce } from '@gravityforms/utils'; const { useEffect, useRef, useState } = React; /** * @module useAjaxSearch * @description A hook to provide an interface for searching for dropdown list items using AJAX. * * @since 5.6.3 * * @param {object} args The hook arguments. * @param {Function} args.fetchListItems The async function to fetch and return the list items. * @param {boolean} args.ignoreSameValue Whether to ignore the same search value for repeat requests. * @param {Array} args.initialListItems The initial list items. * @param {number} args.minChars The minimum number of characters before a search request is called. * @param {number} args.searchDelay The delay in milliseconds before a search request is called. * * @return {object} The list items and search change function. */ const useAjaxSearch = ( { fetchListItems = async () => {}, ignoreSameValue = true, initialListItems = [], minChars = 2, searchDelay = 500, } ) => { const debounceRef = useRef( null ); const controllerRef = useRef( null ); const lastSearchValue = useRef( '' ); const [ isFetching, setIsFetching ] = useState( false ); const [ listItems, setListItems ] = useState( initialListItems ); /** * @function fetchAndSetListItems * @description Fetches and sets the list items. * * @since 5.6.3 * * @async * * @param {string} value The search value. * @param {object} signal The abort signal. * * @return {void} */ const fetchAndSetListItems = debounce( async ( value, signal ) => { try { setIsFetching( true ); const newListItems = await fetchListItems( value, { signal } ); setIsFetching( false ); setListItems( newListItems ); lastSearchValue.current = value; } catch ( error ) { if ( error.name !== 'AbortError' ) { console.error( 'Error fetching list items for dropdown: ', error ); } } }, { wait: searchDelay } ); /** * @function onSearch * @description The search change function. * * @since 5.6.3 * * @async * * @param {string} value The search value. * * @return {void} */ const onSearch = async ( value ) => { // Clear the debounce timer. if ( debounceRef.current ) { clearTimeout( debounceRef.current ); } // Abort the previous request. if ( controllerRef.current ) { controllerRef.current.abort(); } const controller = new AbortController(); controllerRef.current = controller; const signal = controller.signal; // If the value is the same as the last search value, return. if ( lastSearchValue.current === value && ignoreSameValue ) { return; } // If the value is less than the minChars, return. if ( value.length < minChars && value.length > 0 ) { return; } fetchAndSetListItems( value, signal ); }; // Clean up controller when component unmounts. useEffect( () => { return () => { if ( controllerRef.current ) { controllerRef.current.abort(); } }; }, [] ); return { isFetching, listItems, onSearch, setListItems, }; }; export default useAjaxSearch;