Доки по разработке
This project is maintained by teniryte
npm install @tanstack/react-query
npm install -D @tanstack/react-query-devtools
Опциональные пакеты:
@tanstack/react-query-devtools для инспектора кеша.@tanstack/react-query-persist-client для персистентности.@tanstack/query-sync-storage-persister или @tanstack/query-async-storage-persister для storage-persister.@tanstack/query-broadcast-client-experimental только если вам нужна синхронизация между вкладками и вы принимаете experimental-статус.import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 30_000,
gcTime: 5 * 60_000,
retry: 3,
},
},
})
export function AppProviders({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
Главная идея: в браузере у вас почти всегда должен жить один стабильный QueryClient, а не новый экземпляр на каждый рендер.
stale.stale-запросы автоматически рефетчатся при маунте, возврате фокуса окна и восстановлении сети.3 раза с backoff.5 минут (gcTime).structuralSharing) включено по умолчанию.QueryClientimport { QueryClient } from '@tanstack/react-query'
export function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 60_000,
gcTime: 10 * 60_000,
retry: (failureCount, error) => {
if (error instanceof Response && error.status < 500) return false
return failureCount < 3
},
},
mutations: {
retry: 0,
},
},
})
}
Практика:
staleTime > 0 почти всегда улучшает UX.gcTime: Infinity без причины.retry: 0 или кастомная стратегия понятнее, чем слепой повтор.Официальный паттерн для React 18+/Next.js App Router: новый клиент на сервере, singleton в браузере.
'use client'
import {
isServer,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 60_000,
},
},
})
}
let browserQueryClient: QueryClient | undefined
function getQueryClient() {
if (isServer) return makeQueryClient()
if (!browserQueryClient) browserQueryClient = makeQueryClient()
return browserQueryClient
}
export function Providers({ children }: { children: React.ReactNode }) {
const queryClient = getQueryClient()
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
Почему так:
QueryClient между запросами разных пользователей.import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
<QueryClientProvider client={queryClient}>
<App />
{import.meta.env.DEV ? <ReactQueryDevtools initialIsOpen={false} /> : null}
</QueryClientProvider>
staleTime: Infinity.staleTime от 15s до 60s.1-5 минут.staleTime или ручная инвалидация по событию.staleTime: 'static', если вы не хотите автоматический рефетч даже после инвалидции.new QueryClient() прямо внутри компонента без стабилизации.refetchOnWindowFocus: false без понимания, зачем вы отключаете поведение по умолчанию.QueryClient в браузере.QueryClient на каждый SSR-запрос.staleTime и gcTime.stale не означает “сломанный”, а означает “может требовать фонового обновления”.