diff --git a/docs/react/guides/migrating-to-v5.md b/docs/react/guides/migrating-to-v5.md index 285689c7f3..c5f6ea7370 100644 --- a/docs/react/guides/migrating-to-v5.md +++ b/docs/react/guides/migrating-to-v5.md @@ -462,4 +462,18 @@ See the [TypeScript docs](../typescript#typing-query-options) for more details. See the [useQueries docs](../reference/useQueries#combine) for more details. +### new `useSuspenseQuery` and `useSuspenseInfiniteQuery` hooks + +With v5, suspense for data fetching finally becomes "stable". We've added dedicated hooks that work a bit differently than `useQuery` normally does. The main difference is that they return a tuple of `[data, query]` because you'll mostly care about `data` with this hook (since you don't have to handle pending and error states thanks to suspense). This makes it easy to directly use your data and rename the variable to something else. Further, `data` will never be potentially `undefined` on type level: + +```js +const [post] = useSuspenseQuery({ + // ^? const post: Post + queryKey: ['post', postId], + queryFn: () => fetchPost(postId), +}) +``` + +You can read more about them in the [suspense docs](../guides/suspense). + [//]: # 'NewFeatures' diff --git a/docs/react/guides/suspense.md b/docs/react/guides/suspense.md index 2d8ac8d8f0..cdafe7480a 100644 --- a/docs/react/guides/suspense.md +++ b/docs/react/guides/suspense.md @@ -103,7 +103,7 @@ You can also use the dedicated `useSuspenseQuery` hook to enable suspense mode f ```tsx import { useSuspenseQuery } from '@tanstack/react-query' -const { data } = useSuspenseQuery({ queryKey, queryFn }) +const [data, query] = useSuspenseQuery({ queryKey, queryFn }) ``` This has the same effect as setting the `suspense` option to `true` in the query config, but it works better in TypeScript, because `data` is guaranteed to be defined (as errors and loading states are handled by Suspense- and ErrorBoundaries). diff --git a/docs/react/reference/useSuspenseInfiniteQuery.md b/docs/react/reference/useSuspenseInfiniteQuery.md index 9649a189d7..0f15d9193e 100644 --- a/docs/react/reference/useSuspenseInfiniteQuery.md +++ b/docs/react/reference/useSuspenseInfiniteQuery.md @@ -4,7 +4,7 @@ title: useSuspenseInfiniteQuery --- ```tsx -const result = useSuspenseInfiniteQuery(options) +const [data, query] = useSuspenseInfiniteQuery(options) ``` **Options** @@ -17,7 +17,9 @@ The same as for [useInfiniteQuery](../reference/useInfiniteQuery), except for: **Returns** -Same object as [useInfiniteQuery](../reference/useInfiniteQuery), except for: -- `isPlaceholderData` is missing -- `status` is always `success` - - the derived flags are set accordingly. +A tuple of `[data, query]`, where: +- `data` is the query data +- `query` is the same query object as returned by [useInfiniteQuery](../reference/useInfiniteQuery), except for: + - `isPlaceholderData` is missing + - `status` is always `success` + - the derived flags are set accordingly. diff --git a/docs/react/reference/useSuspenseQuery.md b/docs/react/reference/useSuspenseQuery.md index c716093699..6b0ea65f98 100644 --- a/docs/react/reference/useSuspenseQuery.md +++ b/docs/react/reference/useSuspenseQuery.md @@ -4,7 +4,7 @@ title: useSuspenseQuery --- ```tsx -const result = useSuspenseQuery(options) +const [data, query] = useSuspenseQuery(options) ``` **Options** @@ -17,7 +17,9 @@ The same as for [useQuery](../reference/useQuery), except for: **Returns** -Same object as [useQuery](../reference/useQuery), except for: -- `isPlaceholderData` is missing -- `status` is always `success` - - the derived flags are set accordingly. +A tuple of `[data, query]`, where: +- `data` is the query data +- `query` is the same query object as returned by [useQuery](../reference/useQuery), except for: + - `isPlaceholderData` is missing + - `status` is always `success` + - the derived flags are set accordingly. diff --git a/examples/react/nextjs-suspense-streaming/src/app/page.tsx b/examples/react/nextjs-suspense-streaming/src/app/page.tsx index 7d46a105ae..0e357b1840 100644 --- a/examples/react/nextjs-suspense-streaming/src/app/page.tsx +++ b/examples/react/nextjs-suspense-streaming/src/app/page.tsx @@ -14,8 +14,9 @@ function getBaseURL() { return 'http://localhost:3000' } const baseUrl = getBaseURL() -function useWaitQuery(props: { wait: number }) { - const query = useSuspenseQuery({ + +function MyComponent(props: { wait: number }) { + const [data] = useSuspenseQuery({ queryKey: ['wait', props.wait], queryFn: async () => { const path = `/api/wait?wait=${props.wait}` @@ -31,12 +32,6 @@ function useWaitQuery(props: { wait: number }) { }, }) - return [query.data as string, query] as const -} - -function MyComponent(props: { wait: number }) { - const [data] = useWaitQuery(props) - return
result: {data}
} diff --git a/examples/react/suspense/src/components/Project.jsx b/examples/react/suspense/src/components/Project.jsx index a3ffdb4b09..ddac897839 100644 --- a/examples/react/suspense/src/components/Project.jsx +++ b/examples/react/suspense/src/components/Project.jsx @@ -7,7 +7,7 @@ import Spinner from './Spinner' import { fetchProject } from '../queries' export default function Project({ activeProject, setActiveProject }) { - const { data, isFetching } = useSuspenseQuery({ + const [project, { isFetching }] = useSuspenseQuery({ queryKey: ['project', activeProject], queryFn: () => fetchProject(activeProject), }) @@ -18,13 +18,11 @@ export default function Project({ activeProject, setActiveProject }) {

{activeProject} {isFetching ? : null}

- {data ? ( -
-

forks: {data.forks_count}

-

stars: {data.stargazers_count}

-

watchers: {data.watchers}

-
- ) : null} +
+

forks: {project.forks_count}

+

stars: {project.stargazers_count}

+

watchers: {project.watchers}

+


diff --git a/examples/react/suspense/src/components/Projects.jsx b/examples/react/suspense/src/components/Projects.jsx index 5f652d22a3..ec66069a0e 100644 --- a/examples/react/suspense/src/components/Projects.jsx +++ b/examples/react/suspense/src/components/Projects.jsx @@ -8,7 +8,7 @@ import { fetchProjects, fetchProject } from '../queries' export default function Projects({ setActiveProject }) { const queryClient = useQueryClient() - const { data, isFetching } = useSuspenseQuery({ + const [projects, { isFetching }] = useSuspenseQuery({ queryKey: ['projects'], queryFn: fetchProjects, }) @@ -16,7 +16,7 @@ export default function Projects({ setActiveProject }) { return (

Projects {isFetching ? : null}

- {data.map((project) => ( + {projects.map((project) => (