SuperAPI AI 工具集

tanstack-query-intent-framework-use-suspense-and-error-0e96f8ec

前端与建站

查看项目

更新于 10-16 10:59

技能介绍

本技能是 TanStack Query 在 React 中处理 Suspense 与错误边界的使用指南,建立在 core/fetch-and-observe-queries 与 lifecycle/prefetch-and-remove-request-waterfalls 之上。

用途

用于在使用以下 API 时获得正确写法:useSuspenseQuery、useSuspenseQueries、useSuspenseInfiniteQuery、QueryErrorResetBoundary、throwOnError、useQueryErrorResetBoundary 等。目标是让采用 Suspense 模式的数据获取既能保证数据已定义,又能与错误边界协同完成失败重试。

主要能力与使用方式

基础设置

使用 React 的 Suspense 组件包裹使用 useSuspenseQuery 的组件,并用 fallback 指定加载态:

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

function Todos() {
  const { data } = useSuspenseQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
  })
  return <pre>{JSON.stringify(data)}</pre>
}

export function App() {
  return (
    <Suspense fallback={Loading}>
      <Todos />
    </Suspense>
  )
}

用边界重置查询错误

借助 QueryErrorResetBoundary 与 react-error-boundary 的 ErrorBoundary,在出错时提供重试按钮,重置时调用 reset 以让失败的查询可以重新尝试:

import { QueryErrorResetBoundary } from '@tanstack/react-query'
import { ErrorBoundary } from 'react-error-boundary'

export function QueryErrorBoundary(props: { children: React.ReactNode }) {
  return (
    <QueryErrorResetBoundary>
      {({ reset }) => (
        <ErrorBoundary
          onReset={reset}
          fallbackRender={({ resetErrorBoundary }) => (
            <button onClick={resetErrorBoundary}>Retry</button>
          )}
        >
          {props.children}
        </ErrorBoundary>
      )}
    </QueryErrorResetBoundary>
  )
}

数据必须存在时使用 suspense

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

export function useTodos() {
  return useSuspenseQuery({
    queryKey: ['todos'],
    queryFn: async () => [{ id: 1 }],
  })
}

可禁用流程使用普通查询

当查询需要按条件启用或禁用时,应改用普通的 useQuery:

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

export function useMaybeTodo(id: string | undefined) {
  return useQuery({
    queryKey: ['todo', id],
    queryFn: async () => ({ id }),
    enabled: Boolean(id),
  })
}

常见错误

HIGH:对 suspense 查询使用 disabled

错误写法是对 useSuspenseQuery 传入 enabled。Suspense 钩子保证有数据,不支持像普通查询那样按条件禁用。正确做法是改用 useQuery 并设置 enabled。

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

export function useTodo(id: string | undefined) {
  return useSuspenseQuery({
    queryKey: ['todo', id],
    queryFn: async () => ({ id }),
    enabled: Boolean(id),
  })
}

// 正确
import { useQuery } from '@tanstack/react-query'

export function useTodo(id: string | undefined) {
  return useQuery({
    queryKey: ['todo', id],
    queryFn: async () => ({ id }),
    enabled: Boolean(id),
  })
}

来源:TanStack/query:docs/framework/react/guides/suspense.md

HIGH:缺少重置边界

错误做法是直接使用 useSuspenseQuery 而不提供 QueryErrorResetBoundary。正确做法是用 QueryErrorResetBoundary 包裹 ErrorBoundary,使失败的查询在重置后可以重试:

import { QueryErrorResetBoundary } from '@tanstack/react-query'
import { ErrorBoundary } from 'react-error-boundary'

export function WrappedTodos(props: { children: React.ReactNode }) {
  return (
    <QueryErrorResetBoundary>
      {({ reset }) => (
        <ErrorBoundary onReset={reset} fallback={<p>Error</p>}>
          {props.children}
        </ErrorBoundary>
      )}
    </QueryErrorResetBoundary>
  )
}

来源:TanStack/query:docs/framework/react/reference/QueryErrorResetBoundary.md

MEDIUM:未开启标志就使用 query.promise

稳定的 promise 属性需要实验性的 prefetch-in-render 标志。必须在 QueryClient 的 defaultOptions 中设置 experimental_prefetchInRender: true,否则不应依赖 query.promise:

import { QueryClient, useQuery } from '@tanstack/react-query'

export const queryClient = new QueryClient({
  defaultOptions: { queries: { experimental_prefetchInRender: true } },
})

export function useTodoPromise() {
  return useQuery({ queryKey: ['todo', 1], queryFn: async () => ({ id: 1 }) })
    .promise
}

来源:TanStack/query:docs/framework/react/guides/suspense.md

适用场景

适用于使用 React Suspense 模式与 TanStack Query 进行数据获取、并需要统一错误处理与重试的前端项目。

限制

Suspense 钩子不支持 enabled 这类条件禁用;需要禁用时改用普通查询。稳定 promise 需实验性标志支持。另请参考 lifecycle/ssr-hydration-and-streaming 了解流式注水的约束。其余扩展细节文档暂未提供。