Параметр enabled управляет моментом запуска запроса в
useQuery. По умолчанию любой запрос TanStack Query
выполняется сразу после монтирования компонента. Во многих приложениях
такое поведение неудобно или даже опасно:
Для подобных сценариев используется условное выполнение запросов
через enabled.
Базовый пример:
const query = useQuery({
queryKey: ['profile'],
queryFn: fetchProfile,
enabled: false
})
При enabled: false запрос не будет запускаться
автоматически.
enabledenabled принимает логическое значение:
enabled: true
enabled: false
Также допускается любое выражение, возвращающее boolean:
enabled: !!userId
Если значение:
true — запрос может выполняться;false — запрос находится в неактивном состоянии.Важно понимать: TanStack Query не удаляет запрос из системы. Query продолжает существовать в кэше, но его автоматическое выполнение блокируется.
enabled: falseКогда запрос отключён:
const query = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
enabled: false
})
происходит следующее:
queryFn не вызывается;При этом объект query всё равно содержит состояние:
console.log(query.status)
console.log(query.fetchStatus)
Чаще всего значения будут такими:
status: 'pending'
fetchStatus: 'idle'
Это означает:
Самый распространённый сценарий — выполнение запроса только после появления идентификатора.
Пример:
const userId = user?.id
const postsQuery = useQuery({
queryKey: ['posts', userId],
queryFn: () => fetchPosts(userId),
enabled: !!userId
})
Пока userId отсутствует:
enabled: false
После появления значения:
enabled: true
TanStack Query автоматически запускает запрос.
enabled важенБез условного выполнения легко получить ошибки.
Проблемный код:
const postsQuery = useQuery({
queryKey: ['posts', userId],
queryFn: () => fetchPosts(userId)
})
Если userId равен undefined, приложение
может отправить запрос:
GET /posts/undefined
или:
GET /posts/null
Результат:
Правильный вариант:
const postsQuery = useQuery({
queryKey: ['posts', userId],
queryFn: () => fetchPosts(userId),
enabled: !!userId
})
Одна из главных областей применения enabled — dependent
queries.
Пример:
const userQuery = useQuery({
queryKey: ['user', email],
queryFn: () => fetchUser(email)
})
const projectsQuery = useQuery({
queryKey: ['projects', userQuery.data?.id],
queryFn: () => fetchProjects(userQuery.data.id),
enabled: !!userQuery.data?.id
})
Последовательность работы:
userQuery.projectsQuery отключён.id второй запрос автоматически
стартует.Это один из фундаментальных паттернов TanStack Query.
enabled позволяет строить длинные
последовательности.
Пример:
const sessionQuery = useQuery({
queryKey: ['session'],
queryFn: fetchSession
})
const profileQuery = useQuery({
queryKey: ['profile', sessionQuery.data?.userId],
queryFn: () => fetchProfile(sessionQuery.data.userId),
enabled: !!sessionQuery.data?.userId
})
const settingsQuery = useQuery({
queryKey: ['settings', profileQuery.data?.id],
queryFn: () => fetchSettings(profileQuery.data.id),
enabled: !!profileQuery.data?.id
})
Каждый следующий запрос ожидает завершения предыдущего.
Иногда запрос должен выполняться только по действию пользователя.
Пример:
const query = useQuery({
queryKey: ['report'],
queryFn: fetchReport,
enabled: false
})
Запуск:
<button onCl ick={() => query.refetch()}>
Загрузить отчёт
</button>
В таком сценарии TanStack Query превращается в управляемый механизм загрузки.
enabled от условного рендераМногие разработчики пытаются отключать запрос через условный рендер компонента.
Пример:
{userId && <Posts />}
Это не всегда удобно.
Проблемы:
Часто лучше оставить компонент смонтированным и управлять только запросом:
const query = useQuery({
queryKey: ['posts', userId],
queryFn: () => fetchPosts(userId),
enabled: !!userId
})
enabled и авторизацияОчень частый сценарий — ожидание токена.
const token = authStore.token
const profileQuery = useQuery({
queryKey: ['profile'],
queryFn: () => fetchProfile(token),
enabled: !!token
})
Без этого приложение может отправлять неавторизованные запросы:
401 Unauthorized
enabled может содержать сложную логику.
Пример:
enabled:
isAuthenticated &&
!!userId &&
!isBlocked &&
hasPermission
TanStack Query выполнит запрос только при соблюдении всех условий.
Иногда логика становится слишком сложной для inline-выражений.
Плохой вариант:
enabled:
!!user &&
!!settings &&
!isLoading &&
permissions.includes('admin')
Лучше:
const canLoad = (
!!user &&
!!settings &&
!isLoading &&
permissions.includes('admin')
)
const query = useQuery({
queryKey: ['admin'],
queryFn: fetchAdminData,
enabled: canLoad
})
Так код становится читаемее.
enabled и пустые
строкиОшибка многих разработчиков:
enabled: userId
Если userId — строка:
''
то поведение может быть неочевидным.
Наиболее безопасный вариант:
enabled: !!userId
Двойное отрицание явно приводит значение к boolean.
enabled и числаСледует учитывать особенности JavaScript.
Пример:
enabled: !!id
Если:
id = 0
то результат:
false
Хотя 0 может быть валидным идентификатором.
В таком случае лучше писать:
enabled: id !== undefined
или:
enabled: id != null
enabled и параметры
формыЧасто запрос запускается только после заполнения формы.
Пример поиска:
const searchQuery = useQuery({
queryKey: ['search', search],
queryFn: () => searchUsers(search),
enabled: search.length > 2
})
Пока строка слишком короткая — запрос не выполняется.
enabled и debounceОчень распространённый паттерн:
const debouncedSearch = useDebounce(search, 500)
const query = useQuery({
queryKey: ['search', debouncedSearch],
queryFn: () => searchUsers(debouncedSearch),
enabled: debouncedSearch.length > 2
})
Поведение:
Так уменьшается нагрузка на API.
enabled и SSRПри серверном рендеринге условное выполнение особенно важно.
Например:
enabled: typeof window !== 'undefined'
Это позволяет отключить клиентские запросы на сервере.
Когда enabled меняется:
false → true
TanStack Query автоматически запускает запрос.
Пример:
const [isReady, setIsReady] = useState(false)
const query = useQuery({
queryKey: ['data'],
queryFn: fetchData,
enabled: isReady
})
После:
setIsReady(true)
запрос стартует автоматически.
Если запрос уже был выполнен, а затем:
enabled: false
то:
Пример:
const query = useQuery({
queryKey: ['profile'],
queryFn: fetchProfile,
enabled: isVisible
})
При скрытии блока:
isVisible = false
данные остаются доступными.
enabled не удаляет кэшЭто критически важный момент.
enabled: false
не означает:
cache cleared
Кэш остаётся доступным:
query.data
может содержать старые данные.
staleTimeПример:
const query = useQuery({
queryKey: ['news'],
queryFn: fetchNews,
staleTime: 60000,
enabled: isOnline
})
Если:
isOnline = false
то запросы не выполняются.
После:
isOnline = true
TanStack Query проверяет свежесть данных:
enabled и refetchДаже при отключённом запросе можно вызвать ручное обновление:
const query = useQuery({
queryKey: ['stats'],
queryFn: fetchStats,
enabled: false
})
Запуск:
await query.refetch()
Это важное отличие:
invalidateQueriesЕсли query отключён:
enabled: false
и выполняется:
queryClient.invalidateQueries({
queryKey: ['users']
})
то запрос помечается устаревшим, но автоматически не стартует.
Запуск произойдёт позже:
enabled: true;refetch().queryFnПлохой пример:
const query = useQuery({
queryKey: ['user', userId],
queryFn: fetchUser(userId),
enabled: !!userId
})
Ошибка в том, что функция вызывается немедленно.
Правильно:
const query = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
enabled: !!userId
})
selectenabled хорошо сочетается с трансформацией данных.
const query = useQuery({
queryKey: ['products', categoryId],
queryFn: () => fetchProducts(categoryId),
enabled: !!categoryId,
select: data => data.items
})
Пока категория не выбрана — запрос не выполняется.
TanStack Query официально рассматривает запросы с
enabled: false как lazy queries.
Пример:
const query = useQuery({
queryKey: ['analytics'],
queryFn: fetchAnalytics,
enabled: false
})
Запуск происходит только по необходимости.
enabled
использовать не стоитИногда разработчики чрезмерно усложняют логику.
Плохой пример:
enabled: users.length > 0
если API спокойно возвращает пустой массив.
В таких случаях условное выполнение только усложняет систему.
function UserProjects({ email }) {
const userQuery = useQuery({
queryKey: ['user', email],
queryFn: () => fetchUser(email)
})
const projectsQuery = useQuery({
queryKey: ['projects', userQuery.data?.id],
queryFn: () => fetchProjects(userQuery.data.id),
enabled: !!userQuery.data?.id
})
if (userQuery.isLoading) {
return <div>Загрузка пользователя...</div>
}
if (projectsQuery.isLoading) {
return <div>Загрузка проектов...</div>
}
return (
<ul>
{projectsQuery.data?.map(project => (
<li key={project.id}>
{project.name}
</li>
))}
</ul>
)
}
Здесь реализован полноценный dependent query flow:
id.