TanStack Query хранит результаты запросов в кэше и управляет их жизненным циклом автоматически. Две ключевые настройки, определяющие поведение кэша:
staleTimecacheTime (в новых версиях также используется название
gcTime)Несмотря на внешнюю схожесть, эти параметры решают совершенно разные задачи:
| Опция | Назначение |
|---|---|
staleTime |
Определяет, как долго данные считаются свежими |
cacheTime |
Определяет, как долго неиспользуемый кэш хранится в памяти |
Непонимание различий между ними — одна из самых распространённых причин лишних запросов, устаревших данных и проблем с производительностью.
После успешного выполнения запроса TanStack Query помещает данные в
кэш. Сразу после получения они считаются свежими
(fresh).
Пока данные свежие:
Когда время staleTime истекает, данные становятся
устаревшими (stale).
Важно понимать: устаревшие данные не удаляются. Они продолжают использоваться, но библиотека получает право обновлять их автоматически.
По умолчанию:
staleTime: 0
Это означает:
Пример:
useQuery({
queryKey: ['posts'],
queryFn: fetchPosts
})
Поведение:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 10000
})
Значение:
10000
— это 10 секунд.
Поведение:
| Время | Состояние |
|---|---|
| 0 сек | Запрос выполнен |
| 0–10 сек | Данные fresh |
| После 10 сек | Данные stale |
Пока данные свежие:
const { data } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 10000
})
TanStack Query будет возвращать кэш без повторного запроса.
useQuery({
queryKey: ['profile'],
queryFn: fetchProfile
})
Сценарий:
Так как данные уже stale, библиотека выполнит повторный запрос.
useQuery({
queryKey: ['profile'],
queryFn: fetchProfile,
staleTime: 60000
})
Теперь данные свежие в течение минуты.
Если компонент откроется повторно в пределах 60 секунд:
По умолчанию TanStack Query обновляет stale-запросы при возврате фокуса окна браузера.
Пример:
useQuery({
queryKey: ['notifications'],
queryFn: fetchNotifications
})
Сценарий:
useQuery({
queryKey: ['notifications'],
queryFn: fetchNotifications,
staleTime: 300000
})
Теперь данные считаются свежими 5 минут.
В течение этого времени возврат на вкладку не вызовет новый запрос.
Опция refetchOnMount определяет, нужно ли обновлять
запрос при монтировании компонента.
По умолчанию:
refetchOnMount: true
Но запрос выполняется только если данные stale.
Пример:
useQuery({
queryKey: ['products'],
queryFn: fetchProducts,
staleTime: 20000
})
Если компонент повторно смонтируется через 5 секунд:
Если через 25 секунд:
Иногда данные практически никогда не меняются.
Например:
В таких случаях используют:
staleTime: Infinity
Пример:
useQuery({
queryKey: ['countries'],
queryFn: fetchCountries,
staleTime: Infinity
})
Теперь данные:
const queryClient = useQueryClient()
queryClient.invalidateQueries({
queryKey: ['countries']
})
После инвалидирования:
Например:
staleTime: 0
или:
staleTime: 5000
Например:
staleTime: 60000
Например:
staleTime: Infinity
cacheTime отвечает не за свежесть данных, а за время
хранения неиспользуемого кэша.
Ключевая идея:
inactive);cacheTime.По умолчанию:
cacheTime: 1000 * 60 * 5
То есть:
5 минут
useQuery({
queryKey: ['articles'],
queryFn: fetchArticles,
cacheTime: 300000
})
Сценарий:
Управляет:
Можно ли считать данные актуальными?
Управляет:
Можно ли хранить данные в памяти?
fresh → stale
Данные продолжают существовать.
inactive → garbage collection
Данные полностью удаляются из кэша.
useQuery({
queryKey: ['me'],
queryFn: fetchCurrentUser,
staleTime: 60000,
cacheTime: 300000
})
Поведение:
| Время | Состояние |
|---|---|
| 0–60 сек | Данные fresh |
| После 60 сек | Данные stale |
| После размонтирования | Запускается cacheTime |
| Через 5 минут inactive | Кэш удаляется |
Если cacheTime истёк:
Иногда кэш нужно хранить постоянно.
cacheTime: Infinity
Пример:
useQuery({
queryKey: ['settings'],
queryFn: fetchSettings,
cacheTime: Infinity
})
Теперь кэш:
Слишком долгий cacheTime может привести к:
Особенно опасно:
cacheTime: Infinity
для:
Это распространённая ошибка конфигурации.
Пример:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 600000,
cacheTime: 60000
})
Что происходит:
В результате:
Обычно:
cacheTime >= staleTime
Это позволяет:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60000,
cacheTime: 300000
}
}
})
Теперь все запросы по умолчанию используют эти значения.
useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
staleTime: 10000
})
Локальная настройка имеет приоритет.
staleTime: 0
При переходах между страницами:
staleTime: 300000
Переходы становятся почти мгновенными:
Правильно подобранный staleTime сильно влияет на
пользовательский опыт.
Проблемы:
Проблемы:
| Тип данных | staleTime |
|---|---|
| Чат | 0–5 сек |
| Уведомления | 5–30 сек |
| Список товаров | 1–5 мин |
| Профиль пользователя | 5–30 мин |
| Справочники | Infinity |
TanStack Query Devtools позволяют видеть:
Пример подключения:
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
function App() {
return (
<>
<Routes />
<ReactQueryDevtools initialIsOpen={false} />
</>
)
}
Можно программно управлять запросами:
queryClient.removeQueries({
queryKey: ['posts']
})
Полное удаление:
Инвалидация игнорирует staleTime.
Пример:
queryClient.invalidateQueries({
queryKey: ['todos']
})
Даже если данные были fresh:
staleTime: Infinity
они становятся stale вручную.
Важно понимать:
staleTime
не блокирует refetch полностью.
Запрос всё ещё можно:
const { refetch } = useQuery({
queryKey: ['stats'],
queryFn: fetchStats,
staleTime: Infinity
})
await refetch()
Даже при бесконечном staleTime запрос обновится.
Каждый query хранит:
Большое количество запросов с длинным cacheTime может
существенно увеличить объём памяти.
Особенно в:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60000,
cacheTime: 300000,
refetchOnWindowFocus: false
}
}
})
Такой подход: