Garbage collection в TanStack Query — механизм автоматического удаления неиспользуемых данных из кеша. Он предотвращает бесконтрольный рост памяти приложения и управляет жизненным циклом query после того, как они перестают использоваться компонентами.
В основе работы лежит концепция «неактивных запросов». Пока query используется хотя бы одним observer’ом, данные считаются активными и не подлежат удалению. После размонтирования всех компонентов запрос переходит в состояние inactive и начинает ожидать очистки.
Каждый query внутри Query Cache проходит несколько стадий:
Пример:
const query = useQuery({
queryKey: ['users'],
queryFn: fetchUsers
})
После первого выполнения:
Если компонент размонтируется:
return isVisible ? <Users /> : null
query становится inactive.
После истечения времени garbage collection запись удаляется из кеша.
Query считается неиспользуемым, если:
Пример:
function App() {
const [page, setPage] = useState('users')
return (
<>
{page === 'users' && <UsersPage />}
{page === 'posts' && <PostsPage />}
</>
)
}
При переключении страницы:
setPage('posts')
query ['users'] перестает использоваться и становится
inactive.
В TanStack Query v5 параметр cacheTime был переименован
в gcTime.
Старый вариант:
cacheTime: 300000
Новый вариант:
gcTime: 300000
Оба значения означают:
сколько миллисекунд inactive query хранится в кеше перед удалением
Пример:
const query = useQuery({
queryKey: ['profile'],
queryFn: fetchProfile,
gcTime: 10000
})
Сценарий работы:
<Profile />
Query активен.
null
Query становится inactive.
TanStack Query запускает внутренний timer:
10 секунд
<Profile />
до истечения таймера:
через 10 секунд:
По умолчанию:
gcTime: 5 * 60 * 1000
То есть:
5 минут
Пример эквивалентной настройки:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 300000
}
}
})
Очень распространенная ошибка — путать staleTime и gcTime.
Определяет:
как долго данные считаются свежими
Определяет:
как долго inactive query хранится в кеше
staleTime: 60000
Данные считаются свежими 1 минуту.
gcTime: 300000
Inactive query живет 5 минут.
useQuery({
queryKey: ['settings'],
queryFn: fetchSettings,
staleTime: 60000,
gcTime: 300000
})
Сценарий:
Запрос выполнен.
Данные свежие.
Данные stale, но все еще в кеше.
Query inactive.
Garbage collection удаляет query.
Даже если query stale:
isStale === true
данные продолжают храниться в памяти.
Garbage collection зависит только от:
Даже если gcTime очень маленький:
gcTime: 1000
query не удалится, пока используется компонентом.
Пример:
function Dashboard() {
useQuery({
queryKey: ['stats'],
queryFn: fetchStats,
gcTime: 1000
})
return <div>Dashboard</div>
}
Пока компонент смонтирован:
Можно указать:
gcTime: 0
Пример:
useQuery({
queryKey: ['temp'],
queryFn: fetchTempData,
gcTime: 0
})
После размонтирования:
Полезно для:
Пример:
useQuery({
queryKey: ['wizard-step'],
queryFn: fetchWizardData,
gcTime: 0
})
Можно полностью отключить garbage collection:
gcTime: Infinity
Пример:
useQuery({
queryKey: ['countries'],
queryFn: fetchCountries,
gcTime: Infinity
})
Такой query:
Подходит для:
Пример:
useQuery({
queryKey: ['app-config'],
queryFn: fetchConfig,
staleTime: Infinity,
gcTime: Infinity
})
Проблемы:
Особенно опасно для:
Все query хранятся внутри QueryCache.
const queryClient = new QueryClient()
Внутри:
QueryCache
├── ['users']
├── ['posts']
├── ['profile']
└── ...
Garbage collection удаляет записи именно из QueryCache.
Если query удален:
gcTime expired
то при повторном mount:
useQuery({
queryKey: ['users']
})
TanStack Query:
Если query еще в кеше:
gcTime не истек
то:
useQuery({
queryKey: ['users']
})
может:
Если query inactive:
observer count = 0
background refetch обычно не выполняется.
Garbage collection спокойно удаляет такой query.
Особый случай:
useQuery({
queryKey: ['notifications'],
queryFn: fetchNotifications,
refetchInterval: 5000
})
Если компонент размонтирован:
Prefetch создает query без observer’ов.
Пример:
queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: fetchPosts
})
После prefetch:
Если query не используется:
gcTime expired
данные удаляются.
Часто для prefetch увеличивают gcTime:
queryClient.prefetchQuery({
queryKey: ['products'],
queryFn: fetchProducts,
gcTime: 1000 * 60 * 30
})
Это предотвращает быстрое удаление данных до перехода пользователя на страницу.
При Server-Side Rendering query могут гидратироваться:
dehydrate(queryClient)
После hydration:
При использовании persistence:
persistQueryClient(...)
query сохраняются:
Однако gcTime все равно продолжает работать.
Если query удален garbage collector’ом:
В Devtools можно наблюдать:
Inactive query обычно отображаются отдельно.
function UsersPage() {
const query = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 60000,
gcTime: 300000
})
return (
<div>
{query.data?.map(user => (
<div key={user.id}>
{user.name}
</div>
))}
</div>
)
}
Компонент монтируется.
Выполняется fetch.
Данные кешируются.
Компонент размонтируется.
Query inactive.
Запускается 5-минутный gc timer.
Если компонент не появился снова — query удаляется.
Garbage collection — автоматический механизм, но query можно удалять вручную.
Пример:
queryClient.removeQueries({
queryKey: ['users']
})
TanStack Query:
queryClient.invalidateQueries({
queryKey: ['users']
})
queryClient.removeQueries({
queryKey: ['users']
})
Еще один механизм:
queryClient.resetQueries({
queryKey: ['users']
})
Он:
Это не garbage collection.
В больших приложениях управление garbage collection становится критически важным.
Особенно при:
gcTime: 60000
gcTime: 0
Не все query нужно сохранять.
Избегать огромных payload.
gcTime: Infinity
для всех query.
Результат:
Ошибка:
staleTime: 0
не удаляет query.
Данные просто становятся stale.
gcTime: 1000
может приводить к:
staleTime: Infinity
gcTime: Infinity
staleTime: 60000
gcTime: 300000
gcTime: 0
gcTime: 60000
для предотвращения переполнения памяти.
Garbage collection тесно связан с:
Когда observer count становится равным нулю:
observers.length === 0
TanStack Query:
Библиотека не хранит query бесконечно.
После удаления уничтожаются:
Это особенно важно для SPA, которые работают часами без перезагрузки страницы.
Правильно настроенный gcTime позволяет:
Garbage collection — один из фундаментальных механизмов TanStack Query, обеспечивающий предсказуемое управление кешем и жизненным циклом данных в долгоживущих frontend-приложениях.