import { QueryObserver } from '@tanstack/query-core' import { createMemo } from 'solid-js' import { useBaseQuery } from './useBaseQuery' import type { DefaultError, QueryKey } from '@tanstack/query-core' import type { QueryClient } from './QueryClient' import type { Accessor } from 'solid-js' import type { DefinedUseQueryResult, UseQueryOptions, UseQueryResult, } from './types' import type { DefinedInitialDataOptions, UndefinedInitialDataOptions, } from './queryOptions' /** * Subscribes to a query: a declarative dependency on an asynchronous source of data that is tied to a unique key. * The query runs when the options call for it — `enabled: false` skips the initial fetch. * * This overload is selected when `initialData` is known to be defined, so the resulting `data` is never * `undefined` (unless a `select` changes `TData` to include `undefined`). * @param options - An accessor returning the {@link DefinedInitialDataOptions} to use — everything you can * pass to `useQuery`, 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 current query result, as a Solid store, typed so that `status` is `success` — or `error` if a * fetch attempt fails while keeping the existing data (`status` never resolves to `pending` in this overload's * type, since `initialData` guarantees data upfront). `isSuccess`/`isError` are derived booleans for * convenience. * @see {@link queryOptions} to share these options between `useQuery` and imperative APIs like `queryClient.query`. * @example * ```tsx * import { For } from 'solid-js' * import { useQuery } from '@tanstack/solid-query' * * function Posts() { * // `postsQuery.data` is never `undefined`, thanks to `initialData` — even if a refetch fails, so the * // list stays visible alongside the error. * const postsQuery = useQuery(() => ({ * queryKey: ['posts'], * queryFn: fetchPosts, * initialData: [], * })) * * return ( *
* {postsQuery.isError ? Error: {postsQuery.error.message} : null} * *
* ) * } * ``` */ export function useQuery< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( options: DefinedInitialDataOptions, queryClient?: () => QueryClient, ): DefinedUseQueryResult /** * Subscribes to a query: a declarative dependency on an asynchronous source of data that is tied to a unique key. * The query runs when the options call for it — `enabled: false` skips the initial fetch. * @param options - An accessor returning the {@link UndefinedInitialDataOptions} to use — everything you can * pass to `useQuery`. * @param queryClient - An accessor for a custom `QueryClient`. Otherwise, the one from the nearest context * will be used. * @returns The current query result, as a Solid store. `status` is `pending` if there is no cached data to * display, `error` if the last fetch attempt failed, or `success` if the query has data to display. * `isPending`/`isSuccess`/`isError` are derived booleans for convenience. * @see {@link queryOptions} to share these options between `useQuery` and imperative APIs like `queryClient.query`. * @example * ```tsx * import { For, Match, Switch } from 'solid-js' * import { useQuery } from '@tanstack/solid-query' * * function Posts() { * const postsQuery = useQuery(() => ({ * queryKey: ['posts'], * queryFn: fetchPosts, * })) * * return ( * * Loading... * Error: {postsQuery.error.message} * *
    * {(post) =>
  • {post.title}
  • }
    *
*
{postsQuery.isFetching ? 'Background Updating...' : ' '}
*
*
* ) * } * ``` * @example * `select` derives whatever `data` a component needs from the cached value, without changing what's * actually stored in the cache — the cache still holds the full `Post[]`, but `data` here is a `number`: * ```tsx * import { Match, Switch } from 'solid-js' * import { useQuery } from '@tanstack/solid-query' * * function PostCount() { * const postsQuery = useQuery(() => ({ * queryKey: ['posts'], * queryFn: fetchPosts, * select: (posts) => posts.length, * })) * * return ( * * Loading... * Error: {postsQuery.error.message} * {postsQuery.data} posts * * ) * } * ``` * @example * A dependent query, only enabled once `postId` is set: * ```tsx * import { Match, Switch } from 'solid-js' * import { useQuery } from '@tanstack/solid-query' * * function Post(props: { postId: number | undefined }) { * const postQuery = useQuery(() => ({ * queryKey: ['post', props.postId], * queryFn: () => fetchPost(props.postId!), * enabled: props.postId != null, * })) * * return ( * {postQuery.data?.title}}> * Select a post * Loading... * Error: {postQuery.error.message} * * ) * } * ``` * @example * The same dependent query, using `skipToken` to disable it in a type-safe way instead of relying on * `enabled`. The non-null assertion is still needed — Solid's `props` narrowing doesn't survive into the * `queryFn` closure the way a local `const` would — but `skipToken` keeps `queryFn`'s return type accurate * without it. `refetch` doesn't work while `queryFn` is `skipToken` — use `enabled: false` instead if you * need to trigger the query manually: * ```tsx * import { Match, Switch } from 'solid-js' * import { skipToken, useQuery } from '@tanstack/solid-query' * * function Post(props: { postId: number | undefined }) { * const postQuery = useQuery(() => ({ * queryKey: ['post', props.postId], * queryFn: props.postId != null ? () => fetchPost(props.postId!) : skipToken, * })) * * return ( * {postQuery.data?.title}}> * Select a post * Loading... * Error: {postQuery.error.message} * * ) * } * ``` * @example * Seeding a detail query from an already-cached list, to skip the loading state. `initialDataUpdatedAt` carries * over the list's own fetch time, so that if you set a `staleTime`, it's measured from when the list was * fetched rather than from now: * ```tsx * import { useQuery, useQueryClient } from '@tanstack/solid-query' * * function Post(props: { postId: number }) { * const queryClient = useQueryClient() * * const postQuery = useQuery(() => ({ * queryKey: ['post', props.postId], * queryFn: () => fetchPost(props.postId), * initialData: () => * queryClient * .getQueryData>(['posts']) * ?.find((post) => post.id === props.postId), * initialDataUpdatedAt: () => * queryClient.getQueryState(['posts'])?.dataUpdatedAt, * })) * * return postQuery.isError ? Error: {postQuery.error.message} :

{postQuery.data?.title}

* } * ``` * @example * Paginated data, keeping the previous page's data visible while the next page loads: * ```tsx * import { For, createSignal } from 'solid-js' * import { keepPreviousData, useQuery } from '@tanstack/solid-query' * * function Posts() { * const [page, setPage] = createSignal(0) * * const postsQuery = useQuery(() => ({ * queryKey: ['posts', page()], * queryFn: () => fetchPosts(page()), * placeholderData: keepPreviousData, * })) * * return ( *
*
    * {(post) =>
  • {post.title}
  • }
    *
* *
* ) * } * ``` */ export function useQuery< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( options: UndefinedInitialDataOptions, queryClient?: () => QueryClient, ): UseQueryResult export function useQuery< TQueryFnData, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( options: UseQueryOptions, queryClient?: Accessor, ) { return useBaseQuery( createMemo(() => options()), QueryObserver, queryClient, ) }