Suspense
Preact Query 也可与 Preact 的 Suspense 数据拉取(Data Fetching)API 配合使用。为此,我们提供了专用的 Hook:
启用 suspense 模式后,status 状态和 error 对象将不再需要,并由 Suspense 组件(来自 preact/compat)替代(包括使用 fallback 属性,以及借助错误边界捕获错误)。有关如何配置 suspense 模式的更多信息,请参阅 重置错误边界 章节。
若希望修改(mutation)也像查询(query)一样将错误传播至最近的错误边界,你可将 throwOnError 选项设为 true。
为查询启用 suspense 模式:
1import { useSuspenseQuery } from '@tanstack/preact-query'2 3const { data } = useSuspenseQuery({ queryKey, queryFn })该模式在 TypeScript 中表现良好,因为 data 被保证已定义(错误与加载状态均由 Suspense 和错误边界处理)。
但反过来说,你因此无法有条件地启用或禁用该查询。对于依赖型查询(dependent Queries),这通常并不必要,因为在 suspense 模式下,同一组件内的所有查询会按串行方式拉取。
此查询也不支持 placeholderData。
throwOnError 默认行为
默认情况下,并非所有错误都会抛出至最近的错误边界——仅当没有其他数据可展示时,错误才会被抛出。这意味着:如果某个查询曾在缓存中成功获取过数据,则即使当前数据已过期(stale),组件仍会正常渲染。因此 throwOnError 的默认值为:
1throwOnError: (error, query) => typeof query.state.data === 'undefined'由于你无法更改 throwOnError(否则可能导致 data 变为潜在的 undefined),若希望所有错误均由错误边界统一处理,需手动抛出错误:
1import { useSuspenseQuery } from '@tanstack/preact-query'2 3const { data, error, isFetching } = useSuspenseQuery({ queryKey, queryFn })4 5if (error && !isFetching) {6 throw error7}8 9// continue rendering data重置错误边界
无论你在查询中使用 suspense 还是 throwOnError,都需要一种机制,让查询知晓:在发生错误并重新渲染时,你希望它重试。
查询错误可通过 QueryErrorResetBoundary 组件或 useQueryErrorResetBoundary Hook 重置。
使用组件时,它将在该组件的作用域内重置所有查询错误:
Preact 并未内置错误边界组件,但你可以借助 useErrorBoundary Hook 构建一个:
1import { QueryErrorResetBoundary } from '@tanstack/ppreact-query'2import { useErrorBoundary } from 'preact/hooks'3 4function ErrorBoundary({ children, onReset, fallbackRender }) {5 const [error, resetError] = useErrorBoundary()6 7 if (error) {8 return fallbackRender({9 error,10 resetErrorBoundary: () => {11 onReset()12 resetError()13 },14 })15 }16 17 return children18}19 20const App = () => (21 <QueryErrorResetBoundary>22 {({ reset }) => (23 <ErrorBoundary24 onReset={reset}25 fallbackRender={({ resetErrorBoundary }) => (26 <div>27 There was an error!28 <button onClick={() => resetErrorBoundary()}>Try again</button>29 </div>30 )}31 >32 <Page />33 </ErrorBoundary>34 )}35 </QueryErrorResetBoundary>36)使用 Hook 时,它将在最近的 QueryErrorResetBoundary 作用域内重置所有查询错误;若未定义任何边界,则全局重置:
1import { useQueryErrorResetBoundary } from '@tanstack/ppreact-query'2 3const App = () => {4 const { reset } = useQueryErrorResetBoundary()5 return (6 <ErrorBoundary7 onReset={reset}8 fallbackRender={({ resetErrorBoundary }) => (9 <div>10 There was an error!11 <button onClick={() => resetErrorBoundary()}>Try again</button>12 </div>13 )}14 >15 <Page />16 </ErrorBoundary>17 )18}渲染时拉取(Fetch-on-render) vs 边渲染边拉取(Render-as-you-fetch)
开箱即用时,Preact Query 在 suspense 模式下天然适配 渲染时拉取(Fetch-on-render) 方案,无需额外配置。这意味着:当你的组件尝试挂载时,它们会触发查询拉取并进入 suspend 状态,但仅发生在你导入并挂载这些组件之后。若你想更进一步,实现 边渲染边拉取(Render-as-you-fetch) 模型,我们建议在路由回调和/或用户交互事件中实现 预取(Prefetching),以便在组件挂载前、甚至在其父组件导入或挂载前就启动查询加载。