TanStack Query — библиотека управления асинхронным состоянием в JavaScript-приложениях. Ранее проект был известен как React Query, однако со временем превратился в универсальное решение для разных фреймворков: React, Vue, Solid, Svelte и других.
Главная задача библиотеки — организация получения, кэширования, обновления и синхронизации данных с сервером.
TanStack Query не является глобальным хранилищем состояния наподобие Redux, Zustand или MobX. Библиотека специализируется именно на серверном состоянии.
Под серверным состоянием понимаются данные:
Типичные примеры серверного состояния:
До появления специализированных библиотек загрузка данных обычно выглядела следующим образом:
useEffect(() => {
setLoading(true);
fetch('/api/users')
.then(response => response.json())
.then(data => {
setUsers(data);
})
.finally(() => {
setLoading(false);
});
}, []);
Подобный подход быстро приводит к большому количеству проблем:
В крупных приложениях количество однотипного кода начинает стремительно расти.
TanStack Query строит вокруг серверных данных отдельный слой управления.
Библиотека берет на себя:
Разработчик вместо ручной работы описывает только источник данных.
Пример:
const query = useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
Далее библиотека автоматически:
Одно из важнейших понятий TanStack Query — разделение server state и client state.
Клиентское состояние полностью принадлежит приложению.
Примеры:
const [theme, setTheme] = useState('dark');
const [modalOpen, setModalOpen] = useState(false);
Такое состояние:
Серверное состояние:
Пример:
const fetchUsers = async () => {
const response = await fetch('/api/users');
return response.json();
};
TanStack Query работает именно с этим типом данных.
Внутри TanStack Query используется несколько ключевых сущностей.
QueryClient — центральное хранилище всех запросов.
const queryClient = new QueryClient();
Он управляет:
Каждый запрос сохраняется в специальном кэше.
Кэш содержит:
Каждый запрос идентифицируется ключом.
queryKey: ['users']
Или:
queryKey: ['user', userId]
Query Key играет критически важную роль.
По ключу библиотека:
Функция запроса отвечает за получение данных.
const fetchUsers = async () => {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error('Ошибка загрузки');
}
return response.json();
};
TanStack Query не зависит от конкретного HTTP-клиента.
Можно использовать:
Кэширование — центральный механизм библиотеки.
Когда запрос выполняется впервые:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
TanStack Query:
При повторном использовании:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
библиотека мгновенно возвращает кэшированные данные.
Это значительно ускоряет интерфейс.
В TanStack Query данные считаются устаревшими по умолчанию сразу после получения.
Это важная особенность библиотеки.
Даже если данные присутствуют в кэше, библиотека может инициировать фоновое обновление.
Параметр staleTime определяет время актуальности данных.
useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 60000
});
В течение 60 секунд данные считаются свежими.
До истечения времени:
После истечения:
Одно из ключевых преимуществ библиотеки — фоновое обновление данных.
Сценарий:
Интерфейс при этом:
Пользователь видит старые данные, пока загружаются новые.
TanStack Query предотвращает одинаковые параллельные запросы.
Например:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
Если одновременно несколько компонентов используют одинаковый ключ:
['users']
будет выполнен только один HTTP-запрос.
Остальные компоненты получат общий результат.
Это снижает:
По умолчанию библиотека повторяет неудачные запросы.
useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
retry: 3
});
Если сервер временно недоступен:
Поведение можно настраивать.
Инвалидация сообщает библиотеке, что данные устарели.
Пример:
queryClient.invalidateQueries({
queryKey: ['users']
});
После инвалидирования:
Это особенно важно после мутаций.
TanStack Query разделяет:
Для изменений используется useMutation.
Пример:
const mutation = useMutation({
mutationFn: createUser
});
Мутации применяются для:
После успешной мутации обычно выполняется инвалидирование.
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['users']
});
}
Библиотека поддерживает optimistic updates.
Суть подхода:
Пример сценариев:
Это делает интерфейс значительно более отзывчивым.
Каждый запрос содержит набор состояний.
Пример:
const {
data,
error,
isLoading,
isError,
isSuccess,
isFetching
} = useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
Первичная загрузка.
if (isLoading) {
return <Spinner />;
}
Ошибка запроса.
if (isError) {
return <ErrorMessage error={error} />;
}
Успешное получение данных.
Фоновое обновление.
Очень важное отличие:
TanStack Query превращает серверный кэш в централизованное состояние приложения.
Если несколько компонентов используют один queryKey:
['user', 5]
все они получают синхронизированные данные.
После обновления:
Каждый запрос проходит несколько стадий.
Данные считаются актуальными.
Данные устарели, но все еще доступны.
Компоненты больше не используют запрос.
Через некоторое время неиспользуемые данные удаляются из кэша.
Параметр gcTime управляет временем хранения.
gcTime: 300000
TanStack Query позволяет загружать данные заранее.
Пример:
await queryClient.prefetchQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
Это особенно полезно:
Библиотека поддерживает постраничную загрузку.
Пример pagination:
useQuery({
queryKey: ['users', page],
queryFn: () => fetchUsers(page)
});
Для бесконечной прокрутки используется useInfiniteQuery.
До появления подобных решений серверное состояние часто управлялось вручную через:
Это приводило к:
TanStack Query значительно уменьшает объем инфраструктурного кода.
Минимизация повторных запросов.
Данные автоматически обновляются.
Обновление без блокировки интерфейса.
Защита от одинаковых запросов.
Единая модель обработки.
Библиотека хорошо интегрируется с серверным рендерингом.
TanStack Query Devtools позволяют:
Redux — глобальное хранилище состояния.
TanStack Query — менеджер серверного состояния.
Redux:
TanStack Query:
Во многих современных приложениях TanStack Query полностью заменяет Redux для работы с API.
SWR и TanStack Query решают схожие задачи.
Однако TanStack Query предоставляет:
SWR обычно считается более минималистичным решением.
Библиотека особенно эффективна в приложениях с большим количеством API-запросов:
Для очень простых приложений библиотека иногда оказывается лишней.
Например:
В подобных случаях обычного fetch может быть достаточно.
React Query начинался как библиотека исключительно для React.
Позже проект стал частью экосистемы TanStack:
Это превратило библиотеку в полноценную инфраструктурную платформу.
Главная идея библиотеки — серверное состояние требует отдельного подхода.
Обычное состояние интерфейса и удаленные данные имеют принципиально разную природу.
TanStack Query строится вокруг нескольких фундаментальных принципов:
Именно поэтому TanStack Query стал одним из ключевых инструментов современной frontend-разработки.