Spoosh
Hooks

useInfiniteRead

Bidirectional paginated data fetching with infinite scroll support

Bidirectional paginated data fetching with infinite scroll support.

Basic Usage

function PostList() {
  const {
    data,
    loading,
    canFetchNext,
    canFetchPrev,
    fetchNext,
    fetchPrev,
    fetchingNext,
    fetchingPrev,
  } = useInfiniteRead(
    (api) => api("posts/paginated").GET({ query: { page: 1 } }),
    {
      canFetchNext: ({ response }) => response?.meta.hasMore ?? false,
      nextPageRequest: ({ response, request }) => ({
        query: { ...request.query, page: (response?.meta.page ?? 0) + 1 },
      }),
      merger: (allResponses) => allResponses.flatMap((r) => r.items),
      canFetchPrev: ({ response }) => (response?.meta.page ?? 1) > 1,
      prevPageRequest: ({ response, request }) => ({
        query: { ...request.query, page: (response?.meta.page ?? 2) - 1 },
      }),
    }
  );

  return (
    <div>
      {canFetchPrev && (
        <button onClick={fetchPrev} disabled={fetchingPrev}>
          Load Previous
        </button>
      )}

      {data?.map((post) => <PostCard key={post.id} post={post} />)}

      {canFetchNext && (
        <button onClick={fetchNext} disabled={fetchingNext}>
          Load More
        </button>
      )}
    </div>
  );
}

Options

OptionTypeRequiredDescription
canFetchNext(ctx) => booleanYesCheck if next page exists
nextPageRequest(ctx) => Partial<TRequest>YesBuild request for next page
merger(allResponses) => TItem[]YesMerge all responses into items
canFetchPrev(ctx) => booleanNoCheck if previous page exists
prevPageRequest(ctx) => Partial<TRequest>NoBuild request for previous page
enabledbooleanNoWhether to fetch automatically

Context Object

type Context<TData, TRequest> = {
  response: TData | undefined;
  allResponses: TData[];
  request: TRequest;
};

Returns

PropertyTypeDescription
dataTItem[] | undefinedMerged items from all responses
allResponsesTData[] | undefinedArray of all raw responses
loadingbooleanTrue during initial load
fetchingbooleanTrue during any fetch
fetchingNextbooleanTrue while fetching next page
fetchingPrevbooleanTrue while fetching previous
canFetchNextbooleanWhether next page exists
canFetchPrevbooleanWhether previous page exists
fetchNext() => Promise<void>Fetch the next page
fetchPrev() => Promise<void>Fetch the previous page
refetch() => Promise<void>Refetch all pages
abort() => voidAbort current request
errorTError | undefinedError if request failed
metaobjectPlugin-provided metadata

On this page