Dev Highlights

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

This project is maintained by teniryte

12. Персистентность, офлайн и SSR

Эта глава объединяет три production-сценария:

Персистентность кеша

import { QueryClient } from '@tanstack/react-query'
import { persistQueryClient } from '@tanstack/react-query-persist-client'
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: 24 * 60 * 60 * 1000,
    },
  },
})

persistQueryClient({
  queryClient,
  persister: createSyncStoragePersister({
    storage: window.localStorage,
  }),
  maxAge: 24 * 60 * 60 * 1000,
  buster: 'v1',
})

Важно:

Что сохранять, а что нет

Персистить стоит:

Осторожно с:

Используйте shouldDehydrateQuery, если нужно фильтровать.

Async storage

Для React Native/Expo используется async persister:

Идея та же, отличается только storage backend.

onlineManager и focusManager

Можно переопределять источники событий:

import { onlineManager, focusManager } from '@tanstack/react-query'

onlineManager.setEventListener((setOnline) => {
  window.addEventListener('online', () => setOnline(true))
  window.addEventListener('offline', () => setOnline(false))

  return () => {
    window.removeEventListener('online', () => setOnline(true))
    window.removeEventListener('offline', () => setOnline(false))
  }
})

Это особенно полезно для:

networkMode

Доступные режимы:

Обычно:

Пауза и возобновление мутаций

После восстановления из persister и возврата сети полезно:

await queryClient.resumePausedMutations()

Это особенно важно, если вы храните offline queue.

SSR: базовый порядок действий

  1. Создайте новый QueryClient на сервере.
  2. Выполните prefetchQuery или ensureQueryData.
  3. Вызовите dehydrate(queryClient).
  4. Передайте state в HydrationBoundary.
  5. На клиенте используйте те же query factories.

App Router и Server Components

Современный рекомендуемый подход:

Пример:

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

export default async function PostsPage() {
  const queryClient = new QueryClient()
  await queryClient.prefetchQuery(postsOptions())

  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <PostsClient />
    </HydrationBoundary>
  )
}

Почему на клиенте часто лучше useQuery, а не useSuspenseQuery

Если данные уже были префетчены и гидратированы, обычный useQuery обычно достаточно хорош:

Suspense всё ещё полезен, но не обязателен для уже прогретых запросов.

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