3. Query: useQuery и fetching
Основной инструмент: хук useQuery
Заголовок раздела «Основной инструмент: хук useQuery»useQuery — главный хук TanStack Query для получения данных. Он принимает объект конфигурации
и возвращает объект с данными, статусом и вспомогательными флагами.
const result = useQuery({ queryKey: ['users'], queryFn: () => fetch('/api/users').then(r => r.json()),})queryKey: Ключ запроса
Заголовок раздела «queryKey: Ключ запроса»queryKey — массив значений, уникально идентифицирующий запрос в кэше. Это один из самых важных концептов:
// Простой ключuseQuery({ queryKey: ['users'], queryFn: getUsers })
// Ключ с параметрами (разные пользователи — разные запросы в кэше)useQuery({ queryKey: ['user', userId], queryFn: () => getUser(userId) })
// Ключ с фильтрамиuseQuery({ queryKey: ['users', { status: 'active', page: 1 }], queryFn: getUsers })При изменении queryKey автоматически выполняется новый запрос. Это ключевой механизм реактивности.
queryFn: Функция получения данных
Заголовок раздела «queryFn: Функция получения данных»queryFn — асинхронная функция, которая получает данные. Она должна либо вернуть данные, либо выбросить ошибку:
// С fetchconst queryFn = async () => { const response = await fetch('/api/users') if (!response.ok) throw new Error('Ошибка загрузки') return response.json()}
// С axiosconst queryFn = () => axios.get('/api/users').then(r => r.data)
// Получение параметров из контекстаconst queryFn = ({ queryKey }) => { const [_key, userId] = queryKey return getUser(userId)}Статусы и флаги
Заголовок раздела «Статусы и флаги»useQuery возвращает богатый объект с информацией о состоянии запроса:
const { data, // Данные (undefined до загрузки) error, // Объект ошибки (null при успехе) status, // 'pending' | 'error' | 'success' isLoading, // true только при первой загрузке (нет данных в кэше) isFetching, // true при любой загрузке (включая фоновую) isError, // true при ошибке isSuccess, // true при успехе isPending, // true пока нет данных refetch, // Функция принудительного обновления dataUpdatedAt, // Timestamp последнего обновления} = useQuery({ queryKey, queryFn })Разница между isLoading и isFetching
Заголовок раздела «Разница между isLoading и isFetching»isLoading—trueтолько при первой загрузке (нет данных в кэше)isFetching—trueпри любом активном запросе (включая фоновые обновления)
Используйте isFetching для индикатора фоновой загрузки, isLoading — для скелетона при первой загрузке.
Обработка всех состояний
Заголовок раздела «Обработка всех состояний»function UserList() { const { data, isLoading, isError, error, isFetching } = useQuery({ queryKey: ['users'], queryFn: getUsers, })
if (isLoading) return <Skeleton /> if (isError) return <ErrorMessage message={error.message} />
return ( <> {isFetching && <RefreshIndicator />} <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul> </> )}