1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00
vault-frontend/src/hooks/search/useSearch.ts
2022-01-25 11:24:42 +07:00

70 lines
1.8 KiB
TypeScript

import { useCallback, useEffect, useMemo, useState } from 'react';
import useSWRInfinite, { SWRInfiniteKeyLoader } from 'swr/infinite';
import { getSearchResults } from '~/api/flow';
import { INode } from '~/types';
import { GetSearchResultsRequest } from '~/types/flow';
import { flatten } from '~/utils/ramda';
const RESULTS_COUNT = 20;
const getKey: (text: string) => SWRInfiniteKeyLoader = text => (
pageIndex,
previousPageData: INode[]
) => {
if ((pageIndex > 0 && !previousPageData?.length) || !text) return null;
const props: GetSearchResultsRequest = {
text,
skip: pageIndex * RESULTS_COUNT,
take: RESULTS_COUNT,
};
return JSON.stringify(props);
};
export const useSearch = () => {
const [searchText, setSearchText] = useState('');
const [debouncedSearchText, setDebouncedSearchText] = useState('');
const { data, size, setSize, mutate, isValidating } = useSWRInfinite(
getKey(debouncedSearchText),
async (key: string) => {
const props: GetSearchResultsRequest = key && JSON.parse(key);
if (!props) {
return [] as INode[];
}
const result = await getSearchResults(props);
return result.nodes;
}
);
const loadMore = useCallback(() => setSize(size + 1), [setSize, size]);
const hasMore = (data?.[size - 1]?.length || 0) >= RESULTS_COUNT;
const results = useMemo(() => flatten(data || []), [data]);
useEffect(() => {
const timeout = setTimeout(async () => {
setDebouncedSearchText(searchText.length > 2 ? searchText : '');
await setSize(0);
await mutate([]);
}, 300);
return () => clearTimeout(timeout);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchText]);
return {
results,
searchText,
setSearchText,
hasMore,
loadMore,
isLoading: isValidating,
};
};