snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
121
packages/preact-query/src/useSuspenseQuery.ts
Normal file
121
packages/preact-query/src/useSuspenseQuery.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { QueryObserver, skipToken } from '@tanstack/query-core'
|
||||
import type { DefaultError, QueryClient, QueryKey } from '@tanstack/query-core'
|
||||
|
||||
import { defaultThrowOnError } from './suspense'
|
||||
import type { UseSuspenseQueryOptions, UseSuspenseQueryResult } from './types'
|
||||
import { useBaseQuery } from './useBaseQuery'
|
||||
|
||||
/**
|
||||
* The options for `useSuspenseQuery` are the same as for `useQuery`, except for `throwOnError`, `enabled`, and
|
||||
* `placeholderData`.
|
||||
*
|
||||
* Caveat: cancellation does not work.
|
||||
*
|
||||
* @remarks Multiple `useSuspenseQuery` calls in the same component suspend serially, causing a request
|
||||
* waterfall — each one blocks rendering until it resolves, so the next doesn't even start fetching until then.
|
||||
* Use {@link useSuspenseQueries} instead when you have more than one suspenseful query in a component, so they
|
||||
* fetch in parallel.
|
||||
* @param options - The {@link UseSuspenseQueryOptions} to use — the same options as `useQuery`, minus the ones listed above.
|
||||
* @param queryClient - Use this to use a custom `QueryClient`. Otherwise, the one from the nearest context will
|
||||
* be used.
|
||||
* @returns The same object as `useQuery`, except that `data` is guaranteed to be defined, `isPlaceholderData`
|
||||
* is missing, and `status` is either `success` or `error` (with the derived flags set accordingly).
|
||||
*
|
||||
* @example
|
||||
* The query error is thrown if the fetch fails and no cached data exists yet, so an error boundary is
|
||||
* required around `<Suspense>`. A failed background refetch instead continues to render the cached data.
|
||||
* Use {@link QueryErrorResetBoundary} to let the user retry after such an error:
|
||||
* ```tsx
|
||||
* import { Suspense } from 'preact/compat'
|
||||
* import { useErrorBoundary } from 'preact/hooks'
|
||||
* import { QueryErrorResetBoundary, useSuspenseQuery } from '@tanstack/preact-query'
|
||||
* import type { ComponentChildren } from 'preact'
|
||||
*
|
||||
* function Posts() {
|
||||
* // `data` is guaranteed to be defined here — no `isPending` check needed.
|
||||
* const { data, isFetching } = useSuspenseQuery({
|
||||
* queryKey: ['posts'],
|
||||
* queryFn: fetchPosts,
|
||||
* })
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* <h1>Posts {isFetching ? '(refreshing...)' : null}</h1>
|
||||
* <ul>
|
||||
* {data.map((post) => (
|
||||
* <li key={post.id}>{post.title}</li>
|
||||
* ))}
|
||||
* </ul>
|
||||
* </div>
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* function App() {
|
||||
* return (
|
||||
* <QueryErrorResetBoundary>
|
||||
* {({ reset }) => (
|
||||
* <ErrorBoundary
|
||||
* onReset={reset}
|
||||
* fallbackRender={({ resetErrorBoundary }) => (
|
||||
* <div>
|
||||
* There was an error!
|
||||
* <button onClick={() => resetErrorBoundary()}>Try again</button>
|
||||
* </div>
|
||||
* )}
|
||||
* >
|
||||
* <Suspense fallback={<h1>Loading posts...</h1>}>
|
||||
* <Posts />
|
||||
* </Suspense>
|
||||
* </ErrorBoundary>
|
||||
* )}
|
||||
* </QueryErrorResetBoundary>
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* function ErrorBoundary({
|
||||
* children,
|
||||
* onReset,
|
||||
* fallbackRender,
|
||||
* }: {
|
||||
* children: ComponentChildren
|
||||
* onReset: () => void
|
||||
* fallbackRender: (props: {
|
||||
* error: Error
|
||||
* resetErrorBoundary: () => void
|
||||
* }) => ComponentChildren
|
||||
* }) {
|
||||
* const [error, resetErrorBoundary] = useErrorBoundary(() => onReset())
|
||||
*
|
||||
* if (error) return fallbackRender({ error, resetErrorBoundary })
|
||||
*
|
||||
* return children
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function useSuspenseQuery<
|
||||
TQueryFnData = unknown,
|
||||
TError = DefaultError,
|
||||
TData = TQueryFnData,
|
||||
TQueryKey extends QueryKey = QueryKey,
|
||||
>(
|
||||
options: UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
|
||||
queryClient?: QueryClient,
|
||||
): UseSuspenseQueryResult<TData, TError> {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if ((options.queryFn as any) === skipToken) {
|
||||
console.error('skipToken is not allowed for useSuspenseQuery')
|
||||
}
|
||||
}
|
||||
|
||||
return useBaseQuery(
|
||||
{
|
||||
...options,
|
||||
enabled: true,
|
||||
suspense: true,
|
||||
throwOnError: defaultThrowOnError,
|
||||
placeholderData: undefined,
|
||||
},
|
||||
QueryObserver,
|
||||
queryClient,
|
||||
) as UseSuspenseQueryResult<TData, TError>
|
||||
}
|
||||
Reference in New Issue
Block a user