Batch операции в TanStack Query представляют собой механизм объединения нескольких запросов или мутаций в единые логические или транспортные группы для уменьшения количества сетевых обращений, оптимизации производительности и синхронизации состояния между клиентом и сервером. Концепция батчинга становится особенно важной в приложениях с высокой частотой обновлений данных, сложными графами зависимостей запросов и необходимостью минимизировать нагрузку на API.
В основе batch-операций лежит объединение нескольких логически независимых действий в одно физическое выполнение. В контексте TanStack Query это может касаться как запросов (queries), так и мутаций (mutations), а также внутренних обновлений кеша.
Ключевая цель:
Батчинг не меняет семантику операций, он изменяет способ их исполнения.
TanStack Query использует батчинг внутри себя для оптимизации реактивных обновлений. Когда несколько query или mutation завершаются почти одновременно, библиотека объединяет обновления состояния React, чтобы избежать множественных ререндеров.
Механизм работает на уровне scheduler:
Это особенно заметно при параллельных запросах:
const query1 = useQuery({ queryKey: ['users'], queryFn: fetchUsers });
const query2 = useQuery({ queryKey: ['posts'], queryFn: fetchPosts });
Даже если оба запроса завершаются с небольшой разницей во времени, UI обновится единым блоком.
Одним из наиболее важных сценариев батчинга является инвалидирование кеша.
При вызове:
queryClient.invalidateQueries(['users']);
queryClient.invalidateQueries(['posts']);
TanStack Query группирует эти операции, чтобы:
В результате происходит единый проход по дереву query cache, где совпадающие ключи обрабатываются в одном цикле.
Хотя TanStack Query не предоставляет классического batch API для мутаций, батчинг достигается через композицию mutation-логики и оптимистические обновления.
Типичный пример: массовое обновление сущностей.
const mutation = useMutation({
mutationFn: async (updates) => {
return fetch('/api/batch-update', {
method: 'POST',
body: JSON.stringify(updates),
});
},
});
Однако при отсутствии серверного batch-endpoint батчинг можно эмулировать:
Promise.all([
updateUser({ id: 1, name: 'A' }),
updateUser({ id: 2, name: 'B' }),
updateUser({ id: 3, name: 'C' }),
]);
TanStack Query при этом:
Важной разновидностью batch-оптимизации является дедупликация запросов. TanStack Query автоматически объединяет идентичные запросы, если они:
Пример:
useQuery({ queryKey: ['user', 1], queryFn: fetchUser });
useQuery({ queryKey: ['user', 1], queryFn: fetchUser });
Выполнится один HTTP-запрос, а результат будет разделён между подписчиками.
Это поведение фактически является батчингом на уровне транспортного слоя.
При массовом обновлении кеша TanStack Query позволяет изменять несколько query за один логический проход.
queryClient.setQueriesData(['cart'], (oldData) => {
return oldData.map(item => ({
...item,
price: item.price * 0.9,
}));
});
Если аналогичная операция выполняется для нескольких ключей:
queryClient.setQueriesData(['cart'], updater);
queryClient.setQueriesData(['wishlist'], updater);
queryClient.setQueriesData(['orders'], updater);
внутренний scheduler объединяет обновления состояния, минимизируя количество ререндеров.
TanStack Query тесно связан с React batching model. В React 18 и выше используется автоматический batching, а TanStack Query интегрируется с ним следующим образом:
Это особенно важно при массовых refetch:
queryClient.refetchQueries(['users']);
queryClient.refetchQueries(['posts']);
queryClient.refetchQueries(['comments']);
Даже при последовательных вызовах UI обновится один раз.
При использовании stale-while-revalidate стратегии батчинг проявляется при фоновых refetch:
Пример:
useQuery({
queryKey: ['dashboard'],
queryFn: fetchDashboard,
refetchInterval: 5000,
});
Если одновременно активны несколько таких query, библиотека стремится минимизировать сетевые пики и распределяет обновления по времени.
Глобальная конфигурация позволяет косвенно управлять батчингом поведения:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: true,
staleTime: 10000,
},
},
});
При большом количестве активных query refetchOnWindowFocus может привести к всплеску запросов, однако внутренний batching сглаживает эффект, объединяя обновления кеша и ререндеры.
Наиболее эффективная форма batch-операций достигается при поддержке со стороны API. TanStack Query не навязывает формат, но хорошо работает с batch-endpoint моделями.
Пример серверного батча:
fetch('/api/batch', {
method: 'POST',
body: JSON.stringify({
queries: [
{ endpoint: '/users' },
{ endpoint: '/posts' },
{ endpoint: '/comments' },
],
}),
});
На клиенте:
const queryFn = async () => {
const res = await fetch('/api/batch', {
method: 'POST',
body: JSON.stringify(payload),
});
return res.json();
};
TanStack Query в этом случае получает уже агрегированный результат и минимизирует количество cache operations.
При сложных графах зависимостей кеша батчинг играет ключевую роль. Например:
Без батчинга это приводит к каскаду refetch-запросов.
TanStack Query объединяет такие операции в единый цикл:
Это предотвращает экспоненциальный рост сетевой активности.
Батчинг влияет не только на производительность, но и на архитектуру данных:
При этом важно учитывать, что чрезмерный батчинг может привести к:
Одним из побочных эффектов является изменение временной модели обновлений UI. Вместо последовательного потока обновлений появляется пакетное обновление состояния.
Это выражается в:
TanStack Query стремится сохранить предсказуемость:
Query cache является центральным элементом батчинга. Все операции проходят через него:
Батчинг обеспечивает, что:
Эта модель делает TanStack Query эффективной при работе с большим количеством параллельных запросов и сложными UI-деревьями.