Основы использования useQuery

Хук useQuery является базовым механизмом получения данных в RTK Query и автоматически генерируется для каждого query-endpoint, определённого в createApi. Его основная задача — управлять жизненным циклом HTTP-запроса, кэшированием, повторным использованием данных и состояниями загрузки без ручного управления состоянием в Redux.


Каждый query-endpoint в API-сервисе автоматически превращается в React-хук.

import { createApi, fetchBaseQuery } fr om '@reduxjs/toolkit/query/react';

export const api = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({
    baseUrl: 'https://api.example.com',
  }),
  endpoints: (builder) => ({
    getPosts: builder.query({
      query: () => '/posts',
    }),
  }),
});

export const { useGetPostsQuery } = api;

В данном случае useGetPostsQuery создаётся автоматически и привязывается к endpoint getPosts.


Базовое использование хука

Хук вызывается внутри функционального компонента React и возвращает объект состояния запроса и сами данные.

import { useGetPostsQuery } from './api';

function PostsList() {
  const { data, error, isLoading } = useGetPostsQuery();

  if (isLoading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка загрузки</div>;

  return (
    <ul>
      {data.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

При первом рендере автоматически запускается запрос. Повторные рендеры используют кэшированные данные, если они уже есть.


Аргументы запроса

useQuery принимает аргумент, который передаётся в query-функцию endpoint.

getPostById: builder.query({
  query: (id) => `/posts/${id}`,
});

Использование:

const { data } = useGetPostByIdQuery(5);

Аргумент влияет на ключ кэширования. RTK Query формирует уникальный cache key на основе endpoint и переданных параметров.


Структура возвращаемого объекта

useQuery возвращает объект состояния запроса, включающий ключевые поля:

  • data — результат запроса после успешного выполнения
  • error — объект ошибки при неудачном запросе
  • isLoading — первый запрос ещё выполняется, данных нет
  • isFetching — запрос выполняется (включая фоновые обновления)
  • isSuccess — запрос успешно завершён
  • isError — запрос завершён с ошибкой
  • refetch — функция ручного повторного запроса
const {
  data,
  error,
  isLoading,
  isFetching,
  refetch,
} = useGetPostsQuery();

Различие между isLoading и isFetching принципиально: isLoading относится к первичной загрузке, тогда как isFetching отражает любое текущее получение данных, включая рефетч.


Поведение кэширования

RTK Query сохраняет результат запроса в store и повторно использует его при повторном обращении к тому же endpoint с теми же аргументами.

При наличии кэшированных данных:

  • повторный вызов хука не инициирует новый запрос мгновенно
  • данные возвращаются из кэша
  • фоновое обновление может происходить при необходимости

Управление автоматическим выполнением запроса

RTK Query позволяет управлять поведением запроса через опции хука.

skip — условное отключение запроса

const { data } = useGetPostByIdQuery(id, {
  skip: !id,
});

Если skip равен true, запрос не выполняется и состояние не инициализируется.


pollingInterval — периодическое обновление

const { data } = useGetPostsQuery(undefined, {
  pollingInterval: 5000,
});

Запрос будет повторяться каждые 5 секунд, пока компонент смонтирован.


refetchOnMountOrArgChange

useGetPostsQuery(undefined, {
  refetchOnMountOrArgChange: true,
});

Определяет, должен ли запрос выполняться при каждом монтировании компонента или изменении аргументов, даже если данные уже есть в кэше.


refetchOnFocus

useGetPostsQuery(undefined, {
  refetchOnFocus: true,
});

Активирует повторный запрос при возврате фокуса на вкладку браузера.


refetchOnReconnect

useGetPostsQuery(undefined, {
  refetchOnReconnect: true,
});

Запускает повторный запрос при восстановлении сетевого соединения.


Параметры аргумента и сериализация

Аргумент запроса используется RTK Query для построения ключа кэша. Сериализация выполняется автоматически, но важно учитывать структуру данных.

useGetPostsQuery({ page: 1, lim it: 10 });

RTK Query интерпретирует объект как уникальный идентификатор запроса. Изменение порядка ключей объекта может повлиять на кэширование, поэтому рекомендуется использовать стабильные структуры данных.


Повторный запрос через refetch

Функция refetch инициирует принудительное обновление данных независимо от кэша.

const { data, refetch } = useGetPostsQuery();

<button onCl ick={() => refetch()}>Обновить</button>;

При вызове выполняется новый запрос к серверу, а кэш обновляется.


Состояние загрузки и повторные рендеры

Каждое изменение состояния запроса вызывает повторный рендер компонента. RTK Query оптимизирует обновления так, чтобы не выполнять лишние перерендеры при неизменных данных.

Основные сценарии:

  • первый рендер → isLoading = true
  • завершение запроса → data заполняется, isLoading = false
  • повторный фоновый запрос → isFetching = true, data сохраняется

Работа с аргументами как зависимостями

Изменение аргумента автоматически приводит к новому запросу.

const [page, setPage] = useState(1);

const { data } = useGetPostsQuery(page);

При изменении page RTK Query:

  • сравнивает предыдущий и новый аргумент
  • формирует новый cache key
  • при необходимости выполняет запрос

Пропуск запроса и динамическая логика

Часто запрос необходимо выполнять только при наличии валидных данных.

const userId = props.userId;

const { data } = useGetUserQuery(userId, {
  skip: !userId,
});

Такой подход предотвращает выполнение лишних запросов и снижает нагрузку на сервер.


Поведение при повторном использовании хука

Если один и тот же endpoint используется в нескольких компонентах с одинаковыми аргументами, RTK Query:

  • использует общий кэш
  • не дублирует HTTP-запрос
  • синхронизирует данные между компонентами

Это позволяет строить глобально консистентное состояние без ручной синхронизации.


Инициализация состояния до загрузки данных

Перед выполнением запроса data равен undefined, поэтому важно учитывать начальное состояние:

const { data = [] } = useGetPostsQuery();

Это позволяет избежать ошибок при работе с неинициализированными данными.


Контроль повторной загрузки при изменении сети и фокуса

RTK Query интегрируется с событиями браузера и автоматически реагирует на изменения окружения:

  • потеря соединения → ожидание восстановления
  • восстановление сети → повторный запрос при включённом refetchOnReconnect
  • возврат во вкладку → опциональный рефетч

Синхронизация состояния между компонентами

Если несколько компонентов подписаны на один и тот же query, обновление данных происходит централизованно через store:

  • запрос выполняется один раз
  • все подписчики получают обновление одновременно
  • кэш остаётся единым источником истины

Поведение при изменении жизненного цикла компонента

При размонтировании компонента RTK Query не обязательно удаляет кэш сразу. Данные сохраняются в store до истечения времени или явной очистки, что позволяет повторно использовать их без запроса к серверу при следующем монтировании.