import { InfiniteQueryObserver } from '@tanstack/query-core' import { createMemo } from 'solid-js' import { useBaseQuery } from './useBaseQuery' import type { DefaultError, InfiniteData, QueryKey, QueryObserver, } from '@tanstack/query-core' import type { QueryClient } from './QueryClient' import type { DefinedUseInfiniteQueryResult, UseInfiniteQueryOptions, UseInfiniteQueryResult, } from './types' import type { Accessor } from 'solid-js' import type { DefinedInitialDataInfiniteOptions, UndefinedInitialDataInfiniteOptions, } from './infiniteQueryOptions' /** * The options for `useInfiniteQuery` are identical to `useQuery`, with the addition of * `initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. * * This overload is selected when `initialData` is known to be defined. * @param options - An accessor returning the {@link DefinedInitialDataInfiniteOptions} to use — everything * you can pass to `useInfiniteQuery`, with `initialData` known to be defined. * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context * will be used. * @returns The same properties as `useQuery`, with the addition of `fetchNextPage`, `fetchPreviousPage`, * `hasNextPage`, `hasPreviousPage`, `isFetchingNextPage`, and `isFetchingPreviousPage`. `data.pages` and * `data.pageParams` are also added, as long as a `select` doesn't change `TData` away from its default * `InfiniteData` shape. * @remarks Keep in mind that imperative fetch calls, such as `fetchNextPage`, may interfere with the default * refetch behavior, resulting in outdated data. Make sure to call these functions only in response to user * actions, or add conditions like `hasNextPage && !isFetching`. * @see {@link infiniteQueryOptions} to share these options between `useInfiniteQuery` and imperative APIs like `queryClient.infiniteQuery`. * @example * ```tsx * import { For } from 'solid-js' * import { useInfiniteQuery } from '@tanstack/solid-query' * * function Projects() { * // `projectsQuery.data` is never `undefined`, thanks to `initialData` — even if a refetch fails, so the * // list stays visible alongside the error. * const projectsQuery = useInfiniteQuery(() => ({ * queryKey: ['projects'], * queryFn: ({ pageParam }) => fetchProjects(pageParam), * initialPageParam: 0, * getNextPageParam: (lastPage) => lastPage.nextId, * initialData: { pages: [], pageParams: [] }, * })) * * return ( *
* {projectsQuery.isError ? Error: {projectsQuery.error.message} : null} * *
* ) * } * ``` */ export function useInfiniteQuery< TQueryFnData, TError = DefaultError, TData = InfiniteData, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown, >( options: DefinedInitialDataInfiniteOptions< TQueryFnData, TError, TData, TQueryKey, TPageParam >, queryClient?: Accessor, ): DefinedUseInfiniteQueryResult /** * The options for `useInfiniteQuery` are identical to `useQuery`, with the addition of * `initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. * @param options - An accessor returning the {@link UndefinedInitialDataInfiniteOptions} to use — everything * you can pass to `useInfiniteQuery`. * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context * will be used. * @returns The same properties as `useQuery`, with the addition of `fetchNextPage`, `fetchPreviousPage`, * `hasNextPage`, `hasPreviousPage`, `isFetchingNextPage`, and `isFetchingPreviousPage`. `data.pages` and * `data.pageParams` are also added, as long as a `select` doesn't change `TData` away from its default * `InfiniteData` shape. * @remarks Keep in mind that imperative fetch calls, such as `fetchNextPage`, may interfere with the default * refetch behavior, resulting in outdated data. Make sure to call these functions only in response to user * actions, or add conditions like `hasNextPage && !isFetching`. * @see {@link infiniteQueryOptions} to share these options between `useInfiniteQuery` and imperative APIs like `queryClient.infiniteQuery`. * @example * Fetching the next page from a "Load More" button click: * ```tsx * import { For, Match, Switch } from 'solid-js' * import { useInfiniteQuery } from '@tanstack/solid-query' * * function Projects() { * const projectsQuery = useInfiniteQuery(() => ({ * queryKey: ['projects'], * queryFn: ({ pageParam }) => fetchProjects(pageParam), * initialPageParam: 0, * getNextPageParam: (lastPage) => lastPage.nextId, * })) * * return ( * * Loading... * Error: {projectsQuery.error.message} * *
    * * {(page) => {(p) =>
  • {p.name}
  • }
    } *
    *
* *
*
* ) * } * ``` * @example * Fetching the next page automatically as the user scrolls, using an `IntersectionObserver` on a * sentinel element after the list: * ```tsx * import { For, Match, Switch, createEffect, onCleanup } from 'solid-js' * import { useInfiniteQuery } from '@tanstack/solid-query' * * function Projects() { * const projectsQuery = useInfiniteQuery(() => ({ * queryKey: ['projects'], * queryFn: ({ pageParam }) => fetchProjects(pageParam), * initialPageParam: 0, * getNextPageParam: (lastPage) => lastPage.nextId, * })) * * let sentinelRef: HTMLDivElement | undefined * * createEffect(() => { * if (sentinelRef == null || !projectsQuery.hasNextPage || projectsQuery.isFetching) return * * const observer = new IntersectionObserver(([entry]) => { * if (entry?.isIntersecting) projectsQuery.fetchNextPage() * }) * observer.observe(sentinelRef) * * onCleanup(() => observer.disconnect()) * }) * * return ( * * Loading... * Error: {projectsQuery.error.message} * *
    * * {(page) => {(p) =>
  • {p.name}
  • }
    } *
    *
*
{projectsQuery.isFetchingNextPage ? 'Loading more...' : null}
*
*
* ) * } * ``` */ export function useInfiniteQuery< TQueryFnData, TError = DefaultError, TData = InfiniteData, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown, >( options: UndefinedInitialDataInfiniteOptions< TQueryFnData, TError, TData, TQueryKey, TPageParam >, queryClient?: Accessor, ): UseInfiniteQueryResult export function useInfiniteQuery< TQueryFnData, TError = DefaultError, TData = InfiniteData, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown, >( options: UseInfiniteQueryOptions< TQueryFnData, TError, TData, TQueryKey, TPageParam >, queryClient?: Accessor, ): UseInfiniteQueryResult { return useBaseQuery( createMemo(() => options()), InfiniteQueryObserver as typeof QueryObserver, queryClient, ) as UseInfiniteQueryResult }