TanStack Query распространяется как отдельный пакет и подключается в
проект через npm, yarn, pnpm или bun. Для React-проектов используется
пакет @tanstack/react-query.
npm install @tanstack/react-query
yarn add @tanstack/react-query
pnpm add @tanstack/react-query
bun add @tanstack/react-query
После установки библиотека становится доступной для импорта в компонентах и конфигурационных файлах приложения.
Для отладки состояния запросов используется отдельный пакет Devtools. Он позволяет просматривать:
npm install @tanstack/react-query-devtools
Вся работа TanStack Query строится вокруг объекта
QueryClient. Он отвечает за:
Обычно экземпляр клиента создаётся один раз на всё приложение.
import { QueryClient } from '@tanstack/react-query';
const queryClient = new QueryClient();
После создания клиента его необходимо передать в React-приложение через провайдер.
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
QueryClient,
QueryClientProvider
} from '@tanstack/react-query';
import App from './App';
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
QueryClientProvider создаёт контекст, через который все
компоненты получают доступ к кешу и механизмам TanStack Query.
Без этого провайдера хуки библиотеки работать не будут.
Devtools обычно подключаются только в режиме разработки.
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
QueryClient,
QueryClientProvider
} from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import App from './App';
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')).render(
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
Параметр initialIsOpen определяет, будет ли панель
открыта сразу после загрузки приложения.
QueryClient поддерживает глобальную конфигурацию. Она
позволяет централизованно задавать поведение всех запросов.
import { QueryClient } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 2,
staleTime: 1000 * 60,
gcTime: 1000 * 60 * 10,
refetchOnWindowFocus: false
}
}
});
Параметр retry определяет количество повторных попыток
запроса при ошибке.
retry: 2
В этом случае запрос выполнится максимум три раза:
retry: false
staleTime определяет время, в течение которого данные
считаются актуальными.
staleTime: 1000 * 60
В данном примере данные остаются свежими одну минуту.
Пока данные считаются актуальными:
Параметр gcTime управляет временем хранения
неиспользуемого кеша.
gcTime: 1000 * 60 * 10
Через десять минут неиспользуемые данные будут удалены из памяти.
В старых версиях React Query этот параметр назывался
cacheTime.
По умолчанию TanStack Query автоматически обновляет данные при возвращении пользователя на вкладку браузера.
refetchOnWindowFocus: false
Отключение этой функции особенно полезно:
TanStack Query не требует строгой структуры каталогов, однако на практике обычно выделяются отдельные директории.
src/
├── api/
│ ├── users.js
│ ├── posts.js
│ └── products.js
│
├── hooks/
│ ├── useUsers.js
│ ├── usePosts.js
│ └── useProducts.js
│
├── components/
│
├── pages/
│
├── query/
│ └── queryClient.js
│
└── App.jsx
Обычно HTTP-запросы выносятся в отдельные модули.
export async function getUsers() {
const response = await fetch(
'https://jsonplaceholder.typicode.com/users'
);
if (!response.ok) {
throw new Error('Ошибка загрузки');
}
return response.json();
}
Такой подход позволяет:
Часто TanStack Query используется вместе с пользовательскими хуками.
import { useQuery } from '@tanstack/react-query';
import { getUsers } from '../api/users';
export function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: getUsers
});
}
import { useUsers } from '../hooks/useUsers';
export default function UsersPage() {
const {
data,
isLoading,
error
} = useUsers();
if (isLoading) {
return <div>Загрузка...</div>;
}
if (error) {
return <div>Ошибка загрузки</div>;
}
return (
<ul>
{data.map(user => (
<li key={user.id}>
{user.name}
</li>
))}
</ul>
);
}
TanStack Query не привязан к конкретному HTTP-клиенту.
Можно использовать:
npm install axios
import axios from 'axios';
export const api = axios.create({
baseURL: 'https://api.example.com'
});
import { api } from './client';
export async function getPosts() {
const response = await api.get('/posts');
return response.data;
}
Глобальная конфигурация позволяет задавать обработчики ошибок.
const queryClient = new QueryClient({
defaultOptions: {
queries: {
onError: error => {
console.error(error);
}
}
}
});
TanStack Query отдельно хранит состояние мутаций.
import {
QueryClient,
MutationCache
} from '@tanstack/react-query';
const queryClient = new QueryClient({
mutationCache: new MutationCache({
onError: error => {
console.error(error);
}
})
});
Для глобального контроля запросов используется
QueryCache.
import {
QueryClient,
QueryCache
} from '@tanstack/react-query';
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: error => {
console.error(error);
}
})
});
Иногда приложение разделяется на независимые области с собственными кешами.
const adminQueryClient = new QueryClient();
const publicQueryClient = new QueryClient();
Такой подход применяется:
TanStack Query позволяет переопределять механизм логирования.
import { QueryClient } from '@tanstack/react-query';
const queryClient = new QueryClient({
logger: {
log: console.log,
warn: console.warn,
error: console.error
}
});
Это позволяет интегрировать:
TanStack Query поддерживает offline-first подход.
const queryClient = new QueryClient({
defaultOptions: {
queries: {
networkMode: 'offlineFirst'
}
}
});
Доступные режимы:
onlinealwaysofflineFirstTanStack Query поддерживает React Suspense.
const queryClient = new QueryClient({
defaultOptions: {
queries: {
suspense: true
}
}
});
import { Suspense } from 'react';
<Suspense fallback={<div>Загрузка...</div>}>
<UsersPage />
</Suspense>
При серверном рендеринге создаётся отдельный экземпляр
QueryClient для каждого запроса.
export function createQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60
}
}
});
}
Изоляция клиента необходима для предотвращения утечки данных между пользователями.
При SSR данные передаются с сервера в клиентский кеш.
import {
HydrationBoundary,
dehydrate
} from '@tanstack/react-query';
dehydrate сериализует кеш, а
HydrationBoundary восстанавливает его на клиенте.
API-адреса обычно выносятся в переменные окружения.
VITE_API_URL=https://api.example.com
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL
});
import {
QueryClient,
QueryCache,
MutationCache
} from '@tanstack/react-query';
export const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: error => {
console.error(error);
}
}),
mutationCache: new MutationCache({
onError: error => {
console.error(error);
}
}),
defaultOptions: {
queries: {
retry: 1,
staleTime: 1000 * 30,
gcTime: 1000 * 60 * 5,
refetchOnWindowFocus: false
}
}
});