diff --git a/docs/framework/preact/reference/functions/infiniteQueryOptions.md b/docs/framework/preact/reference/functions/infiniteQueryOptions.md index d28fe91935..7c1650470a 100644 --- a/docs/framework/preact/reference/functions/infiniteQueryOptions.md +++ b/docs/framework/preact/reference/functions/infiniteQueryOptions.md @@ -9,7 +9,7 @@ title: infiniteQueryOptions function infiniteQueryOptions(options): UseInfiniteQueryOptions & object & QueryKeyWithDataTag, TError>; ``` -Defined in: [preact-query/src/infiniteQueryOptions.ts:157](https://github.com/TanStack/query/blob/main/packages/preact-query/src/infiniteQueryOptions.ts#L157) +Defined in: [preact-query/src/infiniteQueryOptions.ts:167](https://github.com/TanStack/query/blob/main/packages/preact-query/src/infiniteQueryOptions.ts#L167) You can generally pass everything to `infiniteQueryOptions` that you can also pass to `useInfiniteQuery`. These options can be shared across hooks and imperative APIs such as `queryClient.infiniteQuery`. @@ -69,8 +69,18 @@ export const projectsOptions = infiniteQueryOptions({ }) function Projects() { - const { data } = useInfiniteQuery(projectsOptions) - return <>{data.pages.map((page) => page.projects.map((p) =>

{p.name}

))} + // `data` is never `undefined`, thanks to `initialData` — even if a refetch fails, so the + // list stays visible alongside the error. + const { data, isError, error } = useInfiniteQuery(projectsOptions) + + return ( +
+ {isError ? Error: {error.message} : null} +
    + {data.pages.map((page) => page.projects.map((p) =>
  • {p.name}
  • ))} +
+
+ ) } ``` @@ -80,7 +90,7 @@ function Projects() { function infiniteQueryOptions(options): OmitKeyof, "queryFn"> & object & QueryKeyWithDataTag, TError>; ``` -Defined in: [preact-query/src/infiniteQueryOptions.ts:233](https://github.com/TanStack/query/blob/main/packages/preact-query/src/infiniteQueryOptions.ts#L233) +Defined in: [preact-query/src/infiniteQueryOptions.ts:259](https://github.com/TanStack/query/blob/main/packages/preact-query/src/infiniteQueryOptions.ts#L259) You can generally pass everything to `infiniteQueryOptions` that you can also pass to `useInfiniteQuery`. These options can be shared across hooks and imperative APIs such as `queryClient.infiniteQuery`. @@ -123,7 +133,7 @@ The same options object, typed so that `queryKey` carries the inferred data type ### Examples ```tsx -import { infiniteQueryOptions } from '@tanstack/preact-query' +import { infiniteQueryOptions, useInfiniteQuery } from '@tanstack/preact-query' export const projectsOptions = infiniteQueryOptions({ queryKey: ['projects'], @@ -131,6 +141,19 @@ export const projectsOptions = infiniteQueryOptions({ initialPageParam: 0, getNextPageParam: (lastPage) => lastPage.nextId, }) + +function Projects() { + const { data, isPending, isError, error } = useInfiniteQuery(projectsOptions) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data.pages.map((page) => page.projects.map((p) =>
  • {p.name}
  • ))} +
+ ) +} ``` A parameterized factory, reused across a hook and an imperative call with the same cache entry: @@ -150,16 +173,19 @@ export const commentsOptions = (postId: string) => }) function Comments({ postId }: { postId: string }) { - const result = useInfiniteQuery(commentsOptions(postId)) - if (!result.isSuccess) return 'Loading...' + const { data, isPending, isError, error } = useInfiniteQuery(commentsOptions(postId)) + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} return ( - <> - {result.data.pages.map((page) => page.comments.map((c) =>

{c.text}

))} - +
    + {data.pages.map((page) => page.comments.map((c) =>
  • {c.text}
  • ))} +
) } -// Elsewhere, e.g. to warm the cache before rendering ``: +// `commentsOptions` also works with imperative APIs like `queryClient.infiniteQuery` — +// see `useInfiniteQuery` for an example that warms the cache this way before rendering ``. +const postId = '1' queryClient.infiniteQuery(commentsOptions(postId)).catch(noop) ``` @@ -173,7 +199,7 @@ queryClient.infiniteQuery(commentsOptions(postId)).catch(noop) function infiniteQueryOptions(options): UseInfiniteQueryOptions & object & QueryKeyWithDataTag, TError>; ``` -Defined in: [preact-query/src/infiniteQueryOptions.ts:309](https://github.com/TanStack/query/blob/main/packages/preact-query/src/infiniteQueryOptions.ts#L309) +Defined in: [preact-query/src/infiniteQueryOptions.ts:387](https://github.com/TanStack/query/blob/main/packages/preact-query/src/infiniteQueryOptions.ts#L387) You can generally pass everything to `infiniteQueryOptions` that you can also pass to `useInfiniteQuery`. These options can be shared across hooks and imperative APIs such as `queryClient.infiniteQuery`. @@ -216,7 +242,7 @@ The same options object, typed so that `queryKey` carries the inferred data type ### Examples ```tsx -import { infiniteQueryOptions } from '@tanstack/preact-query' +import { infiniteQueryOptions, useInfiniteQuery } from '@tanstack/preact-query' export const projectsOptions = infiniteQueryOptions({ queryKey: ['projects'], @@ -224,6 +250,19 @@ export const projectsOptions = infiniteQueryOptions({ initialPageParam: 0, getNextPageParam: (lastPage) => lastPage.nextId, }) + +function Projects() { + const { data, isPending, isError, error } = useInfiniteQuery(projectsOptions) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data.pages.map((page) => page.projects.map((p) =>
  • {p.name}
  • ))} +
+ ) +} ``` A parameterized factory, reused across a hook and an imperative call with the same cache entry: @@ -243,19 +282,57 @@ export const commentsOptions = (postId: string) => }) function Comments({ postId }: { postId: string }) { - const result = useInfiniteQuery(commentsOptions(postId)) - if (!result.isSuccess) return 'Loading...' + const { data, isPending, isError, error } = useInfiniteQuery(commentsOptions(postId)) + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} return ( - <> - {result.data.pages.map((page) => page.comments.map((c) =>

{c.text}

))} - +
    + {data.pages.map((page) => page.comments.map((c) =>
  • {c.text}
  • ))} +
) } -// Elsewhere, e.g. to warm the cache before rendering ``: +// `commentsOptions` also works with imperative APIs like `queryClient.infiniteQuery` — +// see `useInfiniteQuery` for an example that warms the cache this way before rendering ``. +const postId = '1' queryClient.infiniteQuery(commentsOptions(postId)).catch(noop) ``` +A factory that disables the query, type safe, until `postId` is set: +```tsx +import { + infiniteQueryOptions, + skipToken, + useInfiniteQuery, +} from '@tanstack/preact-query' + +export const commentsOptions = (postId: string | undefined) => + infiniteQueryOptions({ + queryKey: ['post', postId, 'comments'], + queryFn: + postId != null + ? ({ pageParam }) => fetchComments(postId, pageParam) + : skipToken, + initialPageParam: 0, + getNextPageParam: (lastPage) => lastPage.nextId, + }) + +function Comments({ postId }: { postId: string | undefined }) { + // Use `isLoading`, not `isPending`, so the loading state doesn't show while the query is disabled. + const { data, isLoading, isError, error } = useInfiniteQuery(commentsOptions(postId)) + + if (postId == null) return 'Select a post' + if (isLoading) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data?.pages.map((page) => page.comments.map((c) =>
  • {c.text}
  • ))} +
+ ) +} +``` + ### See [useInfiniteQuery](useInfiniteQuery.md) to run an infinite query with these options. diff --git a/docs/framework/preact/reference/functions/queryOptions.md b/docs/framework/preact/reference/functions/queryOptions.md index 88e114030c..3ca9efb150 100644 --- a/docs/framework/preact/reference/functions/queryOptions.md +++ b/docs/framework/preact/reference/functions/queryOptions.md @@ -9,7 +9,7 @@ title: queryOptions function queryOptions(options): Omit, "queryFn"> & object & QueryKeyWithDataTag; ``` -Defined in: [preact-query/src/queryOptions.ts:131](https://github.com/TanStack/query/blob/main/packages/preact-query/src/queryOptions.ts#L131) +Defined in: [preact-query/src/queryOptions.ts:140](https://github.com/TanStack/query/blob/main/packages/preact-query/src/queryOptions.ts#L140) You can generally pass everything to `queryOptions` that you can also pass to `useQuery`. These options can be shared across hooks and imperative APIs such as `queryClient.query`. `options.queryKey` is required and @@ -63,9 +63,18 @@ export const postsOptions = queryOptions({ }) function Posts() { - // `data` is `Post[]`, never `undefined`, thanks to `initialData`. - const { data } = useQuery(postsOptions) - return <>{data.map((post) =>

{post.title}

)} + // `data` is `Post[]`, never `undefined`, thanks to `initialData` — even if a refetch fails, + // so the list stays visible alongside the error. + const { data, isError, error } = useQuery(postsOptions) + + return ( +
+ {isError ? Error: {error.message} : null} +
    + {data.map((post) =>
  • {post.title}
  • )} +
+
+ ) } ``` @@ -75,7 +84,7 @@ function Posts() { function queryOptions(options): OmitKeyof, "queryFn"> & object & QueryKeyWithDataTag; ``` -Defined in: [preact-query/src/queryOptions.ts:201](https://github.com/TanStack/query/blob/main/packages/preact-query/src/queryOptions.ts#L201) +Defined in: [preact-query/src/queryOptions.ts:234](https://github.com/TanStack/query/blob/main/packages/preact-query/src/queryOptions.ts#L234) You can generally pass everything to `queryOptions` that you can also pass to `useQuery`. These options can be shared across hooks and imperative APIs such as `queryClient.query`. `options.queryKey` is required and @@ -118,12 +127,25 @@ The same options object, typed so that `queryKey` carries the inferred data type ### Examples ```tsx -import { queryOptions } from '@tanstack/preact-query' +import { queryOptions, useQuery } from '@tanstack/preact-query' export const postsOptions = queryOptions({ queryKey: ['posts'], queryFn: fetchPosts, }) + +function Posts() { + const { data, isPending, isError, error } = useQuery(postsOptions) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data.map((post) =>
  • {post.title}
  • )} +
+ ) +} ``` A parameterized factory, reused across a hook and an imperative call with the same cache entry: @@ -137,30 +159,41 @@ export const postOptions = (id: string) => }) function Post({ id }: { id: string }) { - const { data } = useQuery(postOptions(id)) - return

{data?.title}

+ const { data, isPending, isError, error } = useQuery(postOptions(id)) + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + return

{data.title}

} -// Elsewhere, e.g. to warm the cache before rendering ``: -queryClient.query(postOptions(id)).catch(noop) +// `postOptions` also works with imperative APIs like `queryClient.query` — +// see `useQuery` for an example that warms the cache this way before rendering ``. +const postId = '1' +queryClient.query(postOptions(postId)).catch(noop) ``` The same options object works with every API that accepts query options: ```tsx -import { - noop, - queryOptions, - useQuery, - useSuspenseQuery, -} from '@tanstack/preact-query' +import { noop, queryOptions, useQuery } from '@tanstack/preact-query' const todosOptions = queryOptions({ queryKey: ['todos'], queryFn: fetchTodos, }) -useQuery(todosOptions) -useSuspenseQuery(todosOptions) +function Todos() { + const { data, isPending, isError, error } = useQuery(todosOptions) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data.map((todo) =>
  • {todo.title}
  • )} +
+ ) +} + +// The same options object works with the imperative APIs too: queryClient.query(todosOptions).catch(noop) queryClient.getQueryData(todosOptions.queryKey) // typed as Array | undefined ``` @@ -171,7 +204,7 @@ queryClient.getQueryData(todosOptions.queryKey) // typed as Array | undefi function queryOptions(options): UseQueryOptions & object & QueryKeyWithDataTag; ``` -Defined in: [preact-query/src/queryOptions.ts:271](https://github.com/TanStack/query/blob/main/packages/preact-query/src/queryOptions.ts#L271) +Defined in: [preact-query/src/queryOptions.ts:350](https://github.com/TanStack/query/blob/main/packages/preact-query/src/queryOptions.ts#L350) You can generally pass everything to `queryOptions` that you can also pass to `useQuery`. These options can be shared across hooks and imperative APIs such as `queryClient.query`. `options.queryKey` is required and @@ -214,12 +247,25 @@ The same options object, typed so that `queryKey` carries the inferred data type ### Examples ```tsx -import { queryOptions } from '@tanstack/preact-query' +import { queryOptions, useQuery } from '@tanstack/preact-query' export const postsOptions = queryOptions({ queryKey: ['posts'], queryFn: fetchPosts, }) + +function Posts() { + const { data, isPending, isError, error } = useQuery(postsOptions) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data.map((post) =>
  • {post.title}
  • )} +
+ ) +} ``` A parameterized factory, reused across a hook and an imperative call with the same cache entry: @@ -233,30 +279,62 @@ export const postOptions = (id: string) => }) function Post({ id }: { id: string }) { - const { data } = useQuery(postOptions(id)) - return

{data?.title}

+ const { data, isPending, isError, error } = useQuery(postOptions(id)) + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + return

{data.title}

} -// Elsewhere, e.g. to warm the cache before rendering ``: -queryClient.query(postOptions(id)).catch(noop) +// `postOptions` also works with imperative APIs like `queryClient.query` — +// see `useQuery` for an example that warms the cache this way before rendering ``. +const postId = '1' +queryClient.query(postOptions(postId)).catch(noop) ``` The same options object works with every API that accepts query options: ```tsx -import { - noop, - queryOptions, - useQuery, - useSuspenseQuery, -} from '@tanstack/preact-query' +import { noop, queryOptions, useQuery } from '@tanstack/preact-query' const todosOptions = queryOptions({ queryKey: ['todos'], queryFn: fetchTodos, }) -useQuery(todosOptions) -useSuspenseQuery(todosOptions) +function Todos() { + const { data, isPending, isError, error } = useQuery(todosOptions) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data.map((todo) =>
  • {todo.title}
  • )} +
+ ) +} + +// The same options object works with the imperative APIs too: queryClient.query(todosOptions).catch(noop) queryClient.getQueryData(todosOptions.queryKey) // typed as Array | undefined ``` + +A factory that disables the query, type safe, until `postId` is set: +```tsx +import { queryOptions, skipToken, useQuery } from '@tanstack/preact-query' + +export const postOptions = (postId: number | undefined) => + queryOptions({ + queryKey: ['post', postId], + queryFn: postId != null ? () => fetchPost(postId) : skipToken, + }) + +function Post({ postId }: { postId: number | undefined }) { + const { data, isLoading, isError, error } = useQuery(postOptions(postId)) + + if (postId == null) return 'Select a post' + if (isLoading) return 'Loading...' + if (isError) return Error: {error.message} + + return

{data?.title}

+} +``` diff --git a/docs/framework/preact/reference/functions/useInfiniteQuery.md b/docs/framework/preact/reference/functions/useInfiniteQuery.md index 3eaadf977b..831cd6fe6a 100644 --- a/docs/framework/preact/reference/functions/useInfiniteQuery.md +++ b/docs/framework/preact/reference/functions/useInfiniteQuery.md @@ -9,7 +9,7 @@ title: useInfiniteQuery function useInfiniteQuery(options, queryClient?): DefinedUseInfiniteQueryResult; ``` -Defined in: [preact-query/src/useInfiniteQuery.ts:55](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useInfiniteQuery.ts#L55) +Defined in: [preact-query/src/useInfiniteQuery.ts:64](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useInfiniteQuery.ts#L64) The options for `useInfiniteQuery` are identical to `useQuery`, with the addition of `queryFn`, `initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. @@ -77,7 +77,9 @@ actions, or add conditions like `hasNextPage && !isFetching`. import { useInfiniteQuery } from '@tanstack/preact-query' function Projects() { - const { data } = useInfiniteQuery({ + // `data` is never `undefined`, thanks to `initialData` — even if a refetch fails, so the + // list stays visible alongside the error. + const { data, isError, error } = useInfiniteQuery({ queryKey: ['projects'], queryFn: ({ pageParam }) => fetchProjects(pageParam), initialPageParam: 0, @@ -85,7 +87,14 @@ function Projects() { initialData: { pages: [], pageParams: [] }, }) - return <>{data.pages.map((page) => page.projects.map((p) =>

{p.name}

))} + return ( +
+ {isError ? Error: {error.message} : null} +
    + {data.pages.map((page) => page.projects.map((p) =>
  • {p.name}
  • ))} +
+
+ ) } ``` @@ -95,7 +104,7 @@ function Projects() { function useInfiniteQuery(options, queryClient?): UseInfiniteQueryResult; ``` -Defined in: [preact-query/src/useInfiniteQuery.ts:115](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useInfiniteQuery.ts#L115) +Defined in: [preact-query/src/useInfiniteQuery.ts:142](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useInfiniteQuery.ts#L142) The options for `useInfiniteQuery` are identical to `useQuery`, with the addition of `queryFn`, `initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. @@ -161,25 +170,43 @@ actions, or add conditions like `hasNextPage && !isFetching`. import { useInfiniteQuery } from '@tanstack/preact-query' function Projects() { - const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } = - useInfiniteQuery({ - queryKey: ['projects'], - queryFn: ({ pageParam }) => fetchProjects(pageParam), - initialPageParam: 0, - getNextPageParam: (lastPage) => lastPage.nextId, - }) + const { + data, + isPending, + isError, + error, + fetchNextPage, + hasNextPage, + isFetching, + isFetchingNextPage, + } = useInfiniteQuery({ + queryKey: ['projects'], + queryFn: ({ pageParam }) => fetchProjects(pageParam), + initialPageParam: 0, + getNextPageParam: (lastPage) => lastPage.nextId, + }) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} return ( - + <> +
    + {data.pages.map((page) => + page.projects.map((project) =>
  • {project.name}
  • ), + )} +
+ + ) } ``` @@ -190,7 +217,7 @@ function Projects() { function useInfiniteQuery(options, queryClient?): UseInfiniteQueryResult; ``` -Defined in: [preact-query/src/useInfiniteQuery.ts:175](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useInfiniteQuery.ts#L175) +Defined in: [preact-query/src/useInfiniteQuery.ts:294](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useInfiniteQuery.ts#L294) The options for `useInfiniteQuery` are identical to `useQuery`, with the addition of `queryFn`, `initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. @@ -250,31 +277,121 @@ actions, or add conditions like `hasNextPage && !isFetching`. [infiniteQueryOptions](infiniteQueryOptions.md) to share these options between `useInfiniteQuery` and imperative APIs like `queryClient.infiniteQuery`. -### Example +### Examples ```tsx import { useInfiniteQuery } from '@tanstack/preact-query' function Projects() { - const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } = - useInfiniteQuery({ - queryKey: ['projects'], - queryFn: ({ pageParam }) => fetchProjects(pageParam), - initialPageParam: 0, - getNextPageParam: (lastPage) => lastPage.nextId, - }) + const { + data, + isPending, + isError, + error, + fetchNextPage, + hasNextPage, + isFetching, + isFetchingNextPage, + } = useInfiniteQuery({ + queryKey: ['projects'], + queryFn: ({ pageParam }) => fetchProjects(pageParam), + initialPageParam: 0, + getNextPageParam: (lastPage) => lastPage.nextId, + }) + + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} + + return ( + <> +
    + {data.pages.map((page) => + page.projects.map((project) =>
  • {project.name}
  • ), + )} +
+ + + ) +} +``` +Warming the cache on hover, so `` has data as soon as it's clicked. Requires an +[infiniteQueryOptions](infiniteQueryOptions.md) factory, so the hook and the imperative call share the same cache entry: +```tsx +import { + infiniteQueryOptions, + noop, + useInfiniteQuery, + useQueryClient, +} from '@tanstack/preact-query' + +const commentsOptions = (postId: string) => + infiniteQueryOptions({ + queryKey: ['post', postId, 'comments'], + queryFn: ({ pageParam }) => fetchComments(postId, pageParam), + initialPageParam: 0, + getNextPageParam: (lastPage) => lastPage.nextId, + }) + +function Comments({ postId }: { postId: string }) { + const { data, isPending, isError, error } = useInfiniteQuery(commentsOptions(postId)) + if (isPending) return 'Loading...' + if (isError) return Error: {error.message} return ( - + {title} + + ) +} +``` + +A query that's disabled, type safe, until `postId` is set — pass `skipToken` as `queryFn` +instead of setting `enabled: false`: +```tsx +import { skipToken, useInfiniteQuery } from '@tanstack/preact-query' + +function Comments({ postId }: { postId: string | undefined }) { + // Use `isLoading`, not `isPending`, so the loading state doesn't show while the query is disabled. + const { data, isLoading, isError, error } = useInfiniteQuery({ + queryKey: ['post', postId, 'comments'], + queryFn: + postId != null + ? ({ pageParam }) => fetchComments(postId, pageParam) + : skipToken, + initialPageParam: 0, + getNextPageParam: (lastPage) => lastPage.nextId, + }) + + if (postId == null) return 'Select a post' + if (isLoading) return 'Loading...' + if (isError) return Error: {error.message} + + return ( +
    + {data?.pages.map((page) => page.comments.map((c) =>
  • {c.text}
  • ))} +
) } ``` diff --git a/docs/framework/preact/reference/functions/useIsFetching.md b/docs/framework/preact/reference/functions/useIsFetching.md index 75aea1a394..915c55fab0 100644 --- a/docs/framework/preact/reference/functions/useIsFetching.md +++ b/docs/framework/preact/reference/functions/useIsFetching.md @@ -7,7 +7,7 @@ title: useIsFetching function useIsFetching(filters?, queryClient?): number; ``` -Defined in: [preact-query/src/useIsFetching.ts:42](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useIsFetching.ts#L42) +Defined in: [preact-query/src/useIsFetching.ts:44](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useIsFetching.ts#L44) `useIsFetching` is an optional hook that returns the `number` of the queries that your application is loading or fetching in the background (useful for app-wide loading indicators). @@ -39,10 +39,12 @@ background. ```tsx import { useIsFetching } from '@tanstack/preact-query' -// How many queries are fetching? -const isFetching = useIsFetching() -// How many queries matching the posts prefix are fetching? -const isFetchingPosts = useIsFetching({ queryKey: ['posts'] }) +function PostsFetchingIndicator() { + // How many queries matching the posts prefix are fetching? + const isFetchingPosts = useIsFetching({ queryKey: ['posts'] }) + + return isFetchingPosts ? Refreshing posts... : null +} ``` A global loading indicator for any query fetching in the background, not just the ones on screen: diff --git a/docs/framework/preact/reference/functions/useIsMutating.md b/docs/framework/preact/reference/functions/useIsMutating.md index 941496a00b..bfc97539bd 100644 --- a/docs/framework/preact/reference/functions/useIsMutating.md +++ b/docs/framework/preact/reference/functions/useIsMutating.md @@ -7,7 +7,7 @@ title: useIsMutating function useIsMutating(filters?, queryClient?): number; ``` -Defined in: [preact-query/src/useMutationState.ts:33](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useMutationState.ts#L33) +Defined in: [preact-query/src/useMutationState.ts:35](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useMutationState.ts#L35) `useIsMutating` is an optional hook that returns the `number` of mutations that your application is fetching (useful for app-wide loading indicators). @@ -38,8 +38,10 @@ Will be the `number` of the mutations that your application is currently fetchin ```tsx import { useIsMutating } from '@tanstack/preact-query' -// How many mutations are fetching? -const isMutating = useIsMutating() -// How many mutations matching the posts prefix are fetching? -const isMutatingPosts = useIsMutating({ mutationKey: ['posts'] }) +function PostsMutatingIndicator() { + // How many mutations matching the posts prefix are in progress? + const isMutatingPosts = useIsMutating({ mutationKey: ['posts'] }) + + return isMutatingPosts ? Saving posts... : null +} ``` diff --git a/docs/framework/preact/reference/functions/useMutation.md b/docs/framework/preact/reference/functions/useMutation.md index f01293841b..a5c6fe1939 100644 --- a/docs/framework/preact/reference/functions/useMutation.md +++ b/docs/framework/preact/reference/functions/useMutation.md @@ -193,13 +193,13 @@ function AddTodos() { }) async function handleAddAll(todos: Array) { - const results = await Promise.allSettled( + const addResults = await Promise.allSettled( todos.map((todo) => addMutation.mutateAsync(todo)), ) - results.forEach((result, index) => { - if (result.status === 'rejected') { - console.error(`Failed to add "${todos[index]}":`, result.reason) + addResults.forEach((addResult, index) => { + if (addResult.status === 'rejected') { + console.error(`Failed to add "${todos[index]}":`, addResult.reason) } }) } diff --git a/docs/framework/preact/reference/functions/useMutationState.md b/docs/framework/preact/reference/functions/useMutationState.md index 6288bff6ef..37bee7a2f6 100644 --- a/docs/framework/preact/reference/functions/useMutationState.md +++ b/docs/framework/preact/reference/functions/useMutationState.md @@ -7,7 +7,7 @@ title: useMutationState function useMutationState(options, queryClient?): TResult[]; ``` -Defined in: [preact-query/src/useMutationState.ts:137](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useMutationState.ts#L137) +Defined in: [preact-query/src/useMutationState.ts:157](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useMutationState.ts#L157) `useMutationState` is a hook that gives you access to all mutations in the `MutationCache`. You can pass `filters` (MutationFilters) to narrow down your mutations, and `select` to transform the mutation @@ -51,10 +51,14 @@ Get all variables of all running mutations: ```tsx import { useMutationState } from '@tanstack/preact-query' -const variables = useMutationState({ - filters: { status: 'pending' }, - select: (mutation) => mutation.state.variables, -}) +function PendingPosts() { + const pendingVariables = useMutationState({ + filters: { status: 'pending' }, + select: (mutation) => mutation.state.variables, + }) + + return <>{pendingVariables.length} posts saving... +} ``` Get all data for specific mutations via the `mutationKey`: @@ -63,27 +67,41 @@ import { useMutation, useMutationState } from '@tanstack/preact-query' const mutationKey = ['posts'] -// Some mutation that we want to get the state for -const mutation = useMutation({ - mutationKey, - mutationFn: createPosts, -}) - -const data = useMutationState({ - // this mutation key needs to match the mutation key of the given mutation (see above) - filters: { mutationKey }, - select: (mutation) => mutation.state.data, -}) +function Posts() { + // Some mutation that we want to get the state for + const mutation = useMutation({ + mutationKey, + mutationFn: createPosts, + }) + + const savedPosts = useMutationState({ + // this mutation key needs to match the mutation key of the given mutation (see above) + filters: { mutationKey, status: 'success' }, + select: (mutation) => mutation.state.data, + }) + + return ( + + ) +} ``` Access the latest mutation data via the `mutationKey`. Each invocation of `mutate` adds a new entry to the mutation cache for `gcTime` milliseconds — check the last item that `useMutationState` returns to get the latest invocation: ```tsx -const data = useMutationState({ - filters: { mutationKey: ['posts'] }, - select: (mutation) => mutation.state.data, -}) +import { useMutationState } from '@tanstack/preact-query' + +function LatestPost() { + const savedPosts = useMutationState({ + filters: { mutationKey: ['posts'], status: 'success' }, + select: (mutation) => mutation.state.data, + }) + + const latestSavedPost = savedPosts[savedPosts.length - 1] -const latest = data[data.length - 1] + return <>{latestSavedPost ? 'Saved' : 'Nothing saved yet'} +} ``` diff --git a/docs/framework/preact/reference/functions/useQueries.md b/docs/framework/preact/reference/functions/useQueries.md index 154077759f..668211e1d3 100644 --- a/docs/framework/preact/reference/functions/useQueries.md +++ b/docs/framework/preact/reference/functions/useQueries.md @@ -7,7 +7,7 @@ title: useQueries function useQueries(__namedParameters, queryClient?): TCombinedResult; ``` -Defined in: [preact-query/src/useQueries.ts:275](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQueries.ts#L275) +Defined in: [preact-query/src/useQueries.ts:301](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQueries.ts#L301) The `useQueries` hook can be used to fetch a variable number of queries. @@ -83,29 +83,55 @@ order as the input. When `combine` is provided, this is the value returned by `c ```tsx import { useQueries } from '@tanstack/preact-query' -const ids = [1, 2, 3] -const results = useQueries({ - queries: ids.map((id) => ({ - queryKey: ['post', id], - queryFn: () => fetchPost(id), - staleTime: Infinity, - })), -}) +function Posts({ ids }: { ids: Array }) { + const postQueries = useQueries({ + queries: ids.map((id) => ({ + queryKey: ['post', id], + queryFn: () => fetchPost(id), + staleTime: Infinity, + })), + }) + + return ( +
    + {postQueries.map((query, index) => { + if (query.isPending) return
  • Loading...
  • + if (query.isError) return
  • Error: {query.error.message}
  • + return
  • {query.data.title}
  • + })} +
+ ) +} ``` Combining results into a single value: ```tsx -const ids = [1, 2, 3] -const combinedQueries = useQueries({ - queries: ids.map((id) => ({ - queryKey: ['post', id], - queryFn: () => fetchPost(id), - })), - combine: (results) => { - return { - data: results.map((result) => result.data), - pending: results.some((result) => result.isPending), - } - }, -}) +import { useQueries } from '@tanstack/preact-query' + +function Posts({ ids }: { ids: Array }) { + const { data, isPending, isError } = useQueries({ + queries: ids.map((id) => ({ + queryKey: ['post', id], + queryFn: () => fetchPost(id), + })), + combine: (postQueries) => { + return { + data: postQueries.map((query) => query.data), + isPending: postQueries.some((query) => query.isPending), + isError: postQueries.some((query) => query.isError), + } + }, + }) + + if (isPending) return 'Loading...' + if (isError) return 'Error loading posts' + + return ( +
    + {data.map((post) => ( +
  • {post?.title}
  • + ))} +
+ ) +} ``` diff --git a/docs/framework/preact/reference/functions/useQuery.md b/docs/framework/preact/reference/functions/useQuery.md index c9d8c943d1..4ce44660c4 100644 --- a/docs/framework/preact/reference/functions/useQuery.md +++ b/docs/framework/preact/reference/functions/useQuery.md @@ -9,7 +9,7 @@ title: useQuery function useQuery(options, queryClient?): DefinedUseQueryResult; ``` -Defined in: [preact-query/src/useQuery.ts:42](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQuery.ts#L42) +Defined in: [preact-query/src/useQuery.ts:50](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQuery.ts#L50) This overload is selected when `initialData` is set, so the resulting `data` is never `undefined`. @@ -64,14 +64,22 @@ since `initialData` guarantees data upfront). `isSuccess`/`isError` are derived import { useQuery } from '@tanstack/preact-query' function Posts() { - // `data` is `Post[]`, never `undefined`, thanks to `initialData`. - const { data } = useQuery({ + // `data` is `Post[]`, never `undefined`, thanks to `initialData` — even if a refetch fails, + // so the list stays visible alongside the error. + const { data, isError, error } = useQuery({ queryKey: ['posts'], queryFn: fetchPosts, initialData: [], }) - return <>{data.map((post) =>

{post.title}

)} + return ( +
+ {isError ? Error: {error.message} : null} +
    + {data.map((post) =>
  • {post.title}
  • )} +
+
+ ) } ``` @@ -81,7 +89,7 @@ function Posts() { function useQuery(options, queryClient?): UseQueryResult; ``` -Defined in: [preact-query/src/useQuery.ts:105](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQuery.ts#L105) +Defined in: [preact-query/src/useQuery.ts:119](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQuery.ts#L119) ### Type Parameters @@ -146,9 +154,11 @@ function Posts() { return (
- {data.map((post) => ( -

{post.title}

- ))} +
    + {data.map((post) => ( +
  • {post.title}
  • + ))} +
{isFetching ? 'Background Updating...' : ' '}
) @@ -168,7 +178,11 @@ function Posts() { if (isPending) return 'Loading...' if (isError) return Error: {error.message} - return <>{data.map((post) =>

{post.title}

)} + return ( +
    + {data.map((post) =>
  • {post.title}
  • )} +
+ ) } ``` @@ -178,7 +192,7 @@ function Posts() { function useQuery(options, queryClient?): UseQueryResult; ``` -Defined in: [preact-query/src/useQuery.ts:221](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQuery.ts#L221) +Defined in: [preact-query/src/useQuery.ts:297](https://github.com/TanStack/query/blob/main/packages/preact-query/src/useQuery.ts#L297) ### Type Parameters @@ -243,9 +257,11 @@ function Posts() { return (
- {data.map((post) => ( -

{post.title}

- ))} +
    + {data.map((post) => ( +
  • {post.title}
  • + ))} +
{isFetching ? 'Background Updating...' : ' '}
) @@ -272,6 +288,27 @@ function Post({ postId }: { postId: number | undefined }) { } ``` +The same dependent query, type safe: `skipToken` disables the query without needing the +non-null assertion above, since `queryFn` is only ever called when `postId` is defined. +`refetch` doesn't work while `queryFn` is `skipToken` — use `enabled: false` instead if you +need to trigger the query manually: +```tsx +import { skipToken, useQuery } from '@tanstack/preact-query' + +function Post({ postId }: { postId: number | undefined }) { + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['post', postId], + queryFn: postId != null ? () => fetchPost(postId) : skipToken, + }) + + if (postId == null) return 'Select a post' + if (isLoading) return 'Loading...' + if (isError) return Error: {error.message} + + return

{data?.title}

+} +``` + Seeding a detail query from an already-cached list, to skip the loading state: ```tsx import { useQuery, useQueryClient } from '@tanstack/preact-query' @@ -279,7 +316,7 @@ import { useQuery, useQueryClient } from '@tanstack/preact-query' function Post({ postId }: { postId: number }) { const queryClient = useQueryClient() - const { data } = useQuery({ + const { data, isError, error } = useQuery({ queryKey: ['post', postId], queryFn: () => fetchPost(postId), initialData: () => @@ -288,6 +325,8 @@ function Post({ postId }: { postId: number }) { ?.find((post) => post.id === postId), }) + if (isError) return Error: {error.message} + return

{data?.title}

} ``` @@ -300,15 +339,19 @@ import { useState } from 'preact/hooks' function Posts() { const [page, setPage] = useState(0) - const { data, isPlaceholderData } = useQuery({ + const { data, isPlaceholderData, isError, error } = useQuery({ queryKey: ['posts', page], queryFn: () => fetchPosts(page), placeholderData: keepPreviousData, }) + if (isError) return Error: {error.message} + return (
- {data?.map((post) =>

{post.title}

)} +
    + {data?.map((post) =>
  • {post.title}
  • )} +
+ * <> + *
    + * {data.pages.map((page) => + * page.projects.map((project) =>
  • {project.name}
  • ), + * )} + *
+ * + * * ) * } * ``` @@ -149,25 +176,117 @@ export function useInfiniteQuery< * import { useInfiniteQuery } from '@tanstack/preact-query' * * function Projects() { - * const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } = - * useInfiniteQuery({ - * queryKey: ['projects'], - * queryFn: ({ pageParam }) => fetchProjects(pageParam), - * initialPageParam: 0, - * getNextPageParam: (lastPage) => lastPage.nextId, - * }) + * const { + * data, + * isPending, + * isError, + * error, + * fetchNextPage, + * hasNextPage, + * isFetching, + * isFetchingNextPage, + * } = useInfiniteQuery({ + * queryKey: ['projects'], + * queryFn: ({ pageParam }) => fetchProjects(pageParam), + * initialPageParam: 0, + * getNextPageParam: (lastPage) => lastPage.nextId, + * }) + * + * if (isPending) return 'Loading...' + * if (isError) return Error: {error.message} * * return ( - * + * + * ) + * } + * ``` + * + * @example + * Warming the cache on hover, so `` has data as soon as it's clicked. Requires an + * {@link infiniteQueryOptions} factory, so the hook and the imperative call share the same cache entry: + * ```tsx + * import { + * infiniteQueryOptions, + * noop, + * useInfiniteQuery, + * useQueryClient, + * } from '@tanstack/preact-query' + * + * const commentsOptions = (postId: string) => + * infiniteQueryOptions({ + * queryKey: ['post', postId, 'comments'], + * queryFn: ({ pageParam }) => fetchComments(postId, pageParam), + * initialPageParam: 0, + * getNextPageParam: (lastPage) => lastPage.nextId, + * }) + * + * function Comments({ postId }: { postId: string }) { + * const { data, isPending, isError, error } = useInfiniteQuery(commentsOptions(postId)) + * if (isPending) return 'Loading...' + * if (isError) return Error: {error.message} + * return ( + *
    + * {data.pages.map((page) => page.comments.map((c) =>
  • {c.text}
  • ))} + *
+ * ) + * } + * + * function PostLink({ postId, title }: { postId: string; title: string }) { + * const queryClient = useQueryClient() + * + * return ( + * queryClient.infiniteQuery(commentsOptions(postId)).catch(noop)} * > - * {isFetchingNextPage - * ? 'Loading more...' - * : hasNextPage - * ? 'Load More' - * : 'Nothing more to load'} - * + * {title} + * + * ) + * } + * ``` + * + * @example + * A query that's disabled, type safe, until `postId` is set — pass `skipToken` as `queryFn` + * instead of setting `enabled: false`: + * ```tsx + * import { skipToken, useInfiniteQuery } from '@tanstack/preact-query' + * + * function Comments({ postId }: { postId: string | undefined }) { + * // Use `isLoading`, not `isPending`, so the loading state doesn't show while the query is disabled. + * const { data, isLoading, isError, error } = useInfiniteQuery({ + * queryKey: ['post', postId, 'comments'], + * queryFn: + * postId != null + * ? ({ pageParam }) => fetchComments(postId, pageParam) + * : skipToken, + * initialPageParam: 0, + * getNextPageParam: (lastPage) => lastPage.nextId, + * }) + * + * if (postId == null) return 'Select a post' + * if (isLoading) return 'Loading...' + * if (isError) return Error: {error.message} + * + * return ( + *
    + * {data?.pages.map((page) => page.comments.map((c) =>
  • {c.text}
  • ))} + *
* ) * } * ``` diff --git a/packages/preact-query/src/useIsFetching.ts b/packages/preact-query/src/useIsFetching.ts index 9deac24f6c..16c00bbf95 100644 --- a/packages/preact-query/src/useIsFetching.ts +++ b/packages/preact-query/src/useIsFetching.ts @@ -19,10 +19,12 @@ import { useSyncExternalStore } from './utils' * ```tsx * import { useIsFetching } from '@tanstack/preact-query' * - * // How many queries are fetching? - * const isFetching = useIsFetching() - * // How many queries matching the posts prefix are fetching? - * const isFetchingPosts = useIsFetching({ queryKey: ['posts'] }) + * function PostsFetchingIndicator() { + * // How many queries matching the posts prefix are fetching? + * const isFetchingPosts = useIsFetching({ queryKey: ['posts'] }) + * + * return isFetchingPosts ? Refreshing posts... : null + * } * ``` * * @example diff --git a/packages/preact-query/src/useMutation.ts b/packages/preact-query/src/useMutation.ts index 68a3759d93..bd4baf0326 100644 --- a/packages/preact-query/src/useMutation.ts +++ b/packages/preact-query/src/useMutation.ts @@ -168,13 +168,13 @@ import { useSyncExternalStore } from './utils' * }) * * async function handleAddAll(todos: Array) { - * const results = await Promise.allSettled( + * const addResults = await Promise.allSettled( * todos.map((todo) => addMutation.mutateAsync(todo)), * ) * - * results.forEach((result, index) => { - * if (result.status === 'rejected') { - * console.error(`Failed to add "${todos[index]}":`, result.reason) + * addResults.forEach((addResult, index) => { + * if (addResult.status === 'rejected') { + * console.error(`Failed to add "${todos[index]}":`, addResult.reason) * } * }) * } diff --git a/packages/preact-query/src/useMutationState.ts b/packages/preact-query/src/useMutationState.ts index beb5318217..58e154a394 100644 --- a/packages/preact-query/src/useMutationState.ts +++ b/packages/preact-query/src/useMutationState.ts @@ -24,10 +24,12 @@ import { useSyncExternalStore } from './utils' * ```tsx * import { useIsMutating } from '@tanstack/preact-query' * - * // How many mutations are fetching? - * const isMutating = useIsMutating() - * // How many mutations matching the posts prefix are fetching? - * const isMutatingPosts = useIsMutating({ mutationKey: ['posts'] }) + * function PostsMutatingIndicator() { + * // How many mutations matching the posts prefix are in progress? + * const isMutatingPosts = useIsMutating({ mutationKey: ['posts'] }) + * + * return isMutatingPosts ? Saving posts... : null + * } * ``` */ export function useIsMutating( @@ -95,10 +97,14 @@ function getResult< * ```tsx * import { useMutationState } from '@tanstack/preact-query' * - * const variables = useMutationState({ - * filters: { status: 'pending' }, - * select: (mutation) => mutation.state.variables, - * }) + * function PendingPosts() { + * const pendingVariables = useMutationState({ + * filters: { status: 'pending' }, + * select: (mutation) => mutation.state.variables, + * }) + * + * return <>{pendingVariables.length} posts saving... + * } * ``` * * @example @@ -108,17 +114,25 @@ function getResult< * * const mutationKey = ['posts'] * - * // Some mutation that we want to get the state for - * const mutation = useMutation({ - * mutationKey, - * mutationFn: createPosts, - * }) - * - * const data = useMutationState({ - * // this mutation key needs to match the mutation key of the given mutation (see above) - * filters: { mutationKey }, - * select: (mutation) => mutation.state.data, - * }) + * function Posts() { + * // Some mutation that we want to get the state for + * const mutation = useMutation({ + * mutationKey, + * mutationFn: createPosts, + * }) + * + * const savedPosts = useMutationState({ + * // this mutation key needs to match the mutation key of the given mutation (see above) + * filters: { mutationKey, status: 'success' }, + * select: (mutation) => mutation.state.data, + * }) + * + * return ( + * + * ) + * } * ``` * * @example @@ -126,12 +140,18 @@ function getResult< * mutation cache for `gcTime` milliseconds — check the last item that `useMutationState` returns to get the * latest invocation: * ```tsx - * const data = useMutationState({ - * filters: { mutationKey: ['posts'] }, - * select: (mutation) => mutation.state.data, - * }) + * import { useMutationState } from '@tanstack/preact-query' + * + * function LatestPost() { + * const savedPosts = useMutationState({ + * filters: { mutationKey: ['posts'], status: 'success' }, + * select: (mutation) => mutation.state.data, + * }) + * + * const latestSavedPost = savedPosts[savedPosts.length - 1] * - * const latest = data[data.length - 1] + * return <>{latestSavedPost ? 'Saved' : 'Nothing saved yet'} + * } * ``` */ export function useMutationState< diff --git a/packages/preact-query/src/useQueries.ts b/packages/preact-query/src/useQueries.ts index c47e5a91b3..a49c29df87 100644 --- a/packages/preact-query/src/useQueries.ts +++ b/packages/preact-query/src/useQueries.ts @@ -244,32 +244,58 @@ export type QueriesResults< * ```tsx * import { useQueries } from '@tanstack/preact-query' * - * const ids = [1, 2, 3] - * const results = useQueries({ - * queries: ids.map((id) => ({ - * queryKey: ['post', id], - * queryFn: () => fetchPost(id), - * staleTime: Infinity, - * })), - * }) + * function Posts({ ids }: { ids: Array }) { + * const postQueries = useQueries({ + * queries: ids.map((id) => ({ + * queryKey: ['post', id], + * queryFn: () => fetchPost(id), + * staleTime: Infinity, + * })), + * }) + * + * return ( + *
    + * {postQueries.map((query, index) => { + * if (query.isPending) return
  • Loading...
  • + * if (query.isError) return
  • Error: {query.error.message}
  • + * return
  • {query.data.title}
  • + * })} + *
+ * ) + * } * ``` * * @example * Combining results into a single value: * ```tsx - * const ids = [1, 2, 3] - * const combinedQueries = useQueries({ - * queries: ids.map((id) => ({ - * queryKey: ['post', id], - * queryFn: () => fetchPost(id), - * })), - * combine: (results) => { - * return { - * data: results.map((result) => result.data), - * pending: results.some((result) => result.isPending), - * } - * }, - * }) + * import { useQueries } from '@tanstack/preact-query' + * + * function Posts({ ids }: { ids: Array }) { + * const { data, isPending, isError } = useQueries({ + * queries: ids.map((id) => ({ + * queryKey: ['post', id], + * queryFn: () => fetchPost(id), + * })), + * combine: (postQueries) => { + * return { + * data: postQueries.map((query) => query.data), + * isPending: postQueries.some((query) => query.isPending), + * isError: postQueries.some((query) => query.isError), + * } + * }, + * }) + * + * if (isPending) return 'Loading...' + * if (isError) return 'Error loading posts' + * + * return ( + *
    + * {data.map((post) => ( + *
  • {post?.title}
  • + * ))} + *
+ * ) + * } * ``` */ export function useQueries< diff --git a/packages/preact-query/src/useQuery.ts b/packages/preact-query/src/useQuery.ts index 0f417095aa..e005fe2f54 100644 --- a/packages/preact-query/src/useQuery.ts +++ b/packages/preact-query/src/useQuery.ts @@ -28,14 +28,22 @@ import { useBaseQuery } from './useBaseQuery' * import { useQuery } from '@tanstack/preact-query' * * function Posts() { - * // `data` is `Post[]`, never `undefined`, thanks to `initialData`. - * const { data } = useQuery({ + * // `data` is `Post[]`, never `undefined`, thanks to `initialData` — even if a refetch fails, + * // so the list stays visible alongside the error. + * const { data, isError, error } = useQuery({ * queryKey: ['posts'], * queryFn: fetchPosts, * initialData: [], * }) * - * return <>{data.map((post) =>

{post.title}

)} + * return ( + *
+ * {isError ? Error: {error.message} : null} + *
    + * {data.map((post) =>
  • {post.title}
  • )} + *
+ *
+ * ) * } * ``` */ @@ -75,9 +83,11 @@ export function useQuery< * * return ( *
- * {data.map((post) => ( - *

{post.title}

- * ))} + *
    + * {data.map((post) => ( + *
  • {post.title}
  • + * ))} + *
*
{isFetching ? 'Background Updating...' : ' '}
*
* ) @@ -98,7 +108,11 @@ export function useQuery< * if (isPending) return 'Loading...' * if (isError) return Error: {error.message} * - * return <>{data.map((post) =>

{post.title}

)} + * return ( + *
    + * {data.map((post) =>
  • {post.title}
  • )} + *
+ * ) * } * ``` */ @@ -138,9 +152,11 @@ export function useQuery< * * return ( *
- * {data.map((post) => ( - *

{post.title}

- * ))} + *
    + * {data.map((post) => ( + *
  • {post.title}
  • + * ))} + *
*
{isFetching ? 'Background Updating...' : ' '}
*
* ) @@ -169,6 +185,28 @@ export function useQuery< * ``` * * @example + * The same dependent query, type safe: `skipToken` disables the query without needing the + * non-null assertion above, since `queryFn` is only ever called when `postId` is defined. + * `refetch` doesn't work while `queryFn` is `skipToken` — use `enabled: false` instead if you + * need to trigger the query manually: + * ```tsx + * import { skipToken, useQuery } from '@tanstack/preact-query' + * + * function Post({ postId }: { postId: number | undefined }) { + * const { data, isLoading, isError, error } = useQuery({ + * queryKey: ['post', postId], + * queryFn: postId != null ? () => fetchPost(postId) : skipToken, + * }) + * + * if (postId == null) return 'Select a post' + * if (isLoading) return 'Loading...' + * if (isError) return Error: {error.message} + * + * return

{data?.title}

+ * } + * ``` + * + * @example * Seeding a detail query from an already-cached list, to skip the loading state: * ```tsx * import { useQuery, useQueryClient } from '@tanstack/preact-query' @@ -176,7 +214,7 @@ export function useQuery< * function Post({ postId }: { postId: number }) { * const queryClient = useQueryClient() * - * const { data } = useQuery({ + * const { data, isError, error } = useQuery({ * queryKey: ['post', postId], * queryFn: () => fetchPost(postId), * initialData: () => @@ -185,6 +223,8 @@ export function useQuery< * ?.find((post) => post.id === postId), * }) * + * if (isError) return Error: {error.message} + * * return

{data?.title}

* } * ``` @@ -198,15 +238,19 @@ export function useQuery< * function Posts() { * const [page, setPage] = useState(0) * - * const { data, isPlaceholderData } = useQuery({ + * const { data, isPlaceholderData, isError, error } = useQuery({ * queryKey: ['posts', page], * queryFn: () => fetchPosts(page), * placeholderData: keepPreviousData, * }) * + * if (isError) return Error: {error.message} + * * return ( *
- * {data?.map((post) =>

{post.title}

)} + *
    + * {data?.map((post) =>
  • {post.title}
  • )} + *
*