added infinite scroll functionality

This commit is contained in:
Nate Kelley 2025-10-01 16:38:11 -06:00
parent 9a9b5fb674
commit 02ce6d6b3a
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
2 changed files with 14 additions and 42 deletions

View File

@ -1,13 +1,9 @@
import type { SearchTextResponse } from '@buster/server-shared/search';
import {
keepPreviousData,
type UseQueryOptions,
useInfiniteQuery,
useQuery,
} from '@tanstack/react-query';
import type { SearchTextData, SearchTextResponse } from '@buster/server-shared/search';
import { keepPreviousData, type UseQueryOptions, useQuery } from '@tanstack/react-query';
import { useState } from 'react';
import type { ApiError } from '@/api/errors';
import { getSearchResultInfinite, searchQueryKeys } from '@/api/query_keys/search';
import { useInfiniteScroll } from '@/api/query-helpers';
import { search } from './requests';
export const useSearch = <T = SearchTextResponse>(
@ -31,17 +27,10 @@ export const useSearchInfinite = (
) => {
const [searchQuery, setSearchQuery] = useState<string>('');
const queryResult = useInfiniteQuery({
const queryResult = useInfiniteScroll<SearchTextData>({
queryKey: ['search', 'results', 'infinite', params] as const,
staleTime: 1000 * 30, // 30 seconds,
staleTime: 1000 * 30, // 30 seconds
queryFn: ({ pageParam = 1 }) => search({ query: searchQuery, page: pageParam, ...params }),
getNextPageParam: (lastPage) => {
if (!lastPage.pagination.has_more) {
return undefined;
}
return lastPage.pagination.page + 1;
},
initialPageParam: 1,
});
return { ...queryResult, setSearchQuery, searchQuery };

View File

@ -1,36 +1,19 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import { createFileRoute } from '@tanstack/react-router';
import { useEffect, useRef } from 'react';
import { search, useSearchInfinite } from '@/api/buster_rest/search';
import { useSearchInfinite } from '@/api/buster_rest/search';
export const Route = createFileRoute('/app/_app/test-pagination')({
component: RouteComponent,
});
function RouteComponent() {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = useSearchInfinite();
const scrollContainerRef = useRef<HTMLDivElement>(null);
// Combine all pages into a single array of results
const allResults = data?.pages.flatMap((page) => page.data) ?? [];
useEffect(() => {
const container = scrollContainerRef.current;
if (!container) return;
const handleScroll = () => {
const { scrollTop, scrollHeight, clientHeight } = container;
// Trigger when user is within 100px of the bottom
if (scrollHeight - scrollTop - clientHeight < 100) {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}
};
container.addEventListener('scroll', handleScroll);
return () => container.removeEventListener('scroll', handleScroll);
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
const {
scrollContainerRef,
allResults,
hasNextPage,
isFetchingNextPage,
isLoading,
fetchNextPage,
} = useSearchInfinite();
return (
<div