import { useDebounceFn, useMemoizedFn } from 'ahooks'; import { useEffect, useState, useTransition } from 'react'; import isEqual from 'lodash/isEqual'; interface UseDebounceSearchProps { items: T[]; searchPredicate: (item: T, searchText: string) => boolean; debounceTime?: number; } export const useDebounceSearch = ({ items, searchPredicate, debounceTime = 150 }: UseDebounceSearchProps) => { const [isPending, startTransition] = useTransition(); const [searchText, setSearchText] = useState(''); const [filteredItems, setFilteredItems] = useState(items); const filterItems = useMemoizedFn((text: string): T[] => { if (!text) return items; const lowerCaseSearchText = text.toLowerCase(); return items.filter((item) => searchPredicate(item, lowerCaseSearchText)); }); const updateFilteredItems = useMemoizedFn((text: string) => { startTransition(() => { setFilteredItems(filterItems(text)); }); }); const { run: debouncedSearch } = useDebounceFn( (text: string) => { updateFilteredItems(text); }, { wait: debounceTime } ); const handleSearchChange = useMemoizedFn((text: string) => { setSearchText(text); if (!text) { updateFilteredItems(text); } else { debouncedSearch(text); } }); useEffect(() => { if (!isEqual(items, filteredItems)) { setFilteredItems(items); } }, [items]); return { filteredItems, searchText, handleSearchChange, isPending }; };