Suspense

React Query 也可以与 React 的 Suspense 数据获取 API 一起使用。为此,我们提供了专用的 Hook:

  • useSuspenseQuery

  • useSuspenseInfiniteQuery

  • useSuspenseQueries

  • 此外,你还可以使用 useQuery().promiseReact.use()(实验性功能)

使用 Suspense 模式时,不再需要 status 状态和 error 对象,而是改用 React.Suspense 组件(包括使用 fallback 属性以及 React 错误边界来捕获错误)。请阅读 重置错误边界 并查看 Suspense 示例,了解如何设置 Suspense 模式。

如果你想让 mutation 也能像 query 一样将错误传播到最近的错误边界,可以将 throwOnError 选项设置为 true

为查询启用 Suspense 模式:

import { useSuspenseQuery } from '@tanstack/react-query'

const { data } = useSuspenseQuery({ queryKey, queryFn })

在 TypeScript 中,这种方式非常友好,因为 data 是有保证的(加载状态和错误由 Suspense 和 ErrorBoundary 处理)。

但反过来说,你因此无法条件性地启用或禁用查询。对于依赖查询,这通常不是问题,因为使用 Suspense 时,组件内的所有查询会串行执行。

此查询也没有 placeholderData。为了防止在更新时 UI 被 fallback 替换,应将更改 QueryKey 的更新操作包裹在 startTransitionarrow-up-right 中。

throwOnError 默认行为

默认情况下,并非所有错误都会抛出到最近的错误边界——我们只在没有其他数据可显示时才抛出错误。这意味着,如果查询曾经成功获取过缓存数据,即使数据已过期(stale),组件也会渲染。因此,throwOnError 的默认值为:

throwOnError: (error, query) => typeof query.state.data === 'undefined'

由于你无法更改 throwOnError(因为这可能导致 data 变为 undefined),如果你想让所有错误都由错误边界处理,则需要手动抛出错误:

重置错误边界

无论你是在查询中使用 suspense 还是 throwOnError,当某个错误发生后重新渲染时,你都需要一种方式来告知查询:你想重试。

可以使用 QueryErrorResetBoundary 组件或 useQueryErrorResetBoundary Hook 来重置查询错误。

使用组件时,它会重置其组件边界内的任何查询错误:

使用 Hook 时,它会重置最近的 QueryErrorResetBoundary 内的任何查询错误。如果没有定义边界,则会全局重置:

渲染时获取 vs 边渲染边获取

开箱即用,React Query 的 suspense 模式可作为 渲染时获取 (Fetch-on-render) 的优秀解决方案,无需额外配置。这意味着当你的组件尝试挂载时,会触发查询并挂起,但仅在你导入并挂载它们时才发生。如果你想更进一步,实现 边渲染边获取 (Render-as-you-fetch) 模型,我们建议在路由回调和/或用户交互事件中实现 预取 (Prefetching),以便在组件挂载前就开始加载查询,甚至在你开始导入或挂载其父组件之前。

服务端的 Suspense 与流式传输

如果你使用的是 NextJs,可以使用我们的 实验性 集成包 @tanstack/react-query-next-experimental 来在服务端使用 Suspense。该包允许你在客户端组件中通过直接调用 useSuspenseQuery 在服务端获取数据。结果将在 Suspense 边界解析时从服务端流式传输到客户端。

要实现此功能,请用 ReactQueryStreamedHydration 组件包裹你的应用:

更多信息,请查看 NextJs Suspense 流式传输示例 和 高级渲染与水合 指南。

使用 useQuery().promiseReact.use()(实验性功能)

要启用此功能,需要在创建 QueryClient 时将 experimental_prefetchInRender 选项设置为 true

示例代码:

使用方法:

更多完整示例,请参见 GitHub 上的 suspense 示例arrow-up-right

Next.js 流式传输示例,请参见 GitHub 上的 nextjs-suspense-streaming 示例arrow-up-right

最后更新于