Dev Highlights

Доки по разработке

This project is maintained by teniryte

10. Suspense и Error Boundaries

TanStack Query глубоко интегрирован с React Suspense. Это особенно полезно в React 18+, App Router и потоковом SSR.

useSuspenseQuery

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

function Article({ slug }: { slug: string }) {
  const query = useSuspenseQuery(articleOptions(slug))
  return <ArticleView article={query.data} />
}

Особенности:

Базовая композиция

<ErrorBoundary fallback={<ErrorState />}>
  <Suspense fallback={<ArticleSkeleton />}>
    <Article slug={slug} />
  </Suspense>
</ErrorBoundary>

Это делает код компонента чище: внутри него не нужно вручную разруливать isPending и isError.

QueryErrorResetBoundary

Чтобы retry после ошибки работал предсказуемо:

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

<QueryErrorResetBoundary>
  {({ reset }) => (
    <ErrorBoundary
      onReset={reset}
      fallbackRender={({ resetErrorBoundary }) => (
        <button onClick={resetErrorBoundary}>Try again</button>
      )}
    >
      <Suspense fallback={<Spinner />}>
        <TodosScreen />
      </Suspense>
    </ErrorBoundary>
  )}
</QueryErrorResetBoundary>

useSuspenseQueries

const [user, projects] = useSuspenseQueries({
  queries: [userOptions(userId), projectsOptions(teamId)],
})

Помните про ограничения актуального API:

useSuspenseInfiniteQuery

const feed = useSuspenseInfiniteQuery({
  queryKey: ['feed'],
  initialPageParam: null,
  queryFn: ({ pageParam }) => fetchFeed(pageParam),
  getNextPageParam: (lastPage) => lastPage.nextCursor,
})

Suspense ждёт первую загрузку. Следующие страницы вы уже контролируете через fetchNextPage.

Когда Suspense особенно уместен

Когда обычный useQuery проще

Важное ограничение: cancellation

Согласно текущей документации, cancellation не работает для:

Если отмена критична, оставайтесь на обычных query hooks.

Prefetch + Suspense = лучший эффект

Самый приятный UX обычно получается так:

  1. делаете prefetch до маунта
  2. оборачиваете экран в Suspense
  3. внутри используете useSuspenseQuery

Тогда Suspense fallback либо не показывается вовсе, либо показывается минимально.

Error Boundary стратегия

Хорошая практика:

Так одна ошибка не уронит весь экран.

Практические рекомендации