The search query string.
Array of manga match results to search.
Configuration options.
Object with results (search results) and isSearching (loading state).
export function useFuzzySearchResults(
searchTerm: string,
matches: MangaMatchResult[],
options: UseFuzzySearchOptions = {},
): {
results: MangaMatchResult[];
isSearching: boolean;
} {
const { debounceMs = 150, enabled = true } = options;
const [results, setResults] = useState<MangaMatchResult[]>(matches);
const [isSearching, setIsSearching] = useState(false);
const debounceTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
const abortControllerRef = useRef<AbortController | undefined>(undefined);
const performSearch = useCallback(
async (query: string, items: MangaMatchResult[]) => {
// Create new abort controller for this search
const abortController = new AbortController();
abortControllerRef.current = abortController;
setIsSearching(true);
try {
const searchResults = await fuzzySearchManga(query, items);
// Only update if this search wasn't aborted
if (!abortController.signal.aborted) {
setResults(searchResults);
}
} catch (error: unknown) {
console.error("[useFuzzySearchResults] Search failed:", error);
// On error, show all matches
if (!abortController.signal.aborted) {
setResults(items);
}
} finally {
if (!abortController.signal.aborted) {
setIsSearching(false);
}
}
},
[],
);
useEffect(() => {
// Clear any pending search
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
// If search is disabled or no search term, show all matches
if (!enabled || !searchTerm.trim()) {
setResults(matches);
setIsSearching(false);
return;
}
// Set up debounced search
setIsSearching(true);
debounceTimerRef.current = setTimeout(() => {
performSearch(searchTerm, matches);
}, debounceMs);
// Cleanup on unmount or when dependencies change
return () => {
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
// Abort any in-flight search
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
};
}, [searchTerm, matches, enabled, debounceMs, performSearch]);
return { results, isSearching };
}
Custom hook for performing debounced fuzzy search with worker pool support.
This hook wraps
fuzzySearchMangato handle async operations and debouncing, making it easy to integrate fuzzy search into React components without blocking the UI.Important: This hook returns a state object with loading and results properties. The results are updated after the debounce delay and search completes.