Предварительная загрузка данных

Предварительная загрузка данных в RTK Query решает задачу уменьшения задержек при переходах между экранами и повышает отзывчивость интерфейса за счёт заблаговременного заполнения кэша. В основе механизма лежит возможность инициировать запрос до того, как соответствующий компонент выполнит подписку через useQuery, что позволяет использовать уже готовые данные без ожидания сетевого ответа.

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

RTK Query предоставляет несколько способов инициировать предварительную загрузку: через dispatch с использованием api.util.prefetch, через хук usePrefetch, а также через стратегическое использование событий интерфейса, таких как наведение курсора, фокус вкладки или появление элемента в области видимости.

Основной низкоуровневый механизм выглядит следующим образом:

dispatch(api.util.prefetch('getPost', postId, { force: false }))

Первый аргумент — имя endpoint, второй — аргумент запроса, третий — параметры управления поведением. Параметр force определяет, следует ли игнорировать существующий кэш и выполнить запрос заново.

Этот подход полезен в ситуациях, когда требуется программное управление предзагрузкой без привязки к React-хукам, например в middleware, эффектах Redux или обработчиках событий вне React.

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

Более удобный способ интеграции в React-компоненты реализован через usePrefetch. Этот хук возвращает функцию, которая инициирует загрузку данных и сохраняет их в кэше RTK Query.

const prefetchPost = api.usePrefetch('getPost')

return (
  <div
    onMouseEn ter={() => prefetchPost(postId)}
  >
    Пост
  </div>
)

В данном случае данные начинают загружаться в момент наведения курсора. Если пользователь затем переходит к странице поста, компонент useGetPostQuery(postId) получает данные мгновенно, без повторного запроса.

Предзагрузка при навигации

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

const prefetchUser = api.usePrefetch('getUser')

<Link
  to={`/user/${id}`}
  onMouseEn ter={() => prefetchUser(id)}
>
  Профиль пользователя
</Link>

Такой подход особенно эффективен в списках, где вероятность перехода по элементу высока, например в таблицах пользователей, каталогах товаров или списках сообщений.

Предварительная загрузка через dispatch

RTK Query позволяет инициировать предзагрузку вне React-слоя через dispatch, что полезно в более сложных сценариях управления состоянием.

import { store } from './store'
import { api } from './api'

store.dispatch(api.util.prefetch('getPost', 42, { force: true }))

Использование force: true заставляет RTK Query игнорировать кэш и перезапрашивать данные. Это применяется в ситуациях, когда необходимо гарантировать актуальность данных заранее, например при критических обновлениях интерфейса или после внешних событий.

Управление жизненным циклом кэша

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

getPost: builder.query({
  query: (id) => `/posts/${id}`,
  keepUnusedDataFor: 60
})

Если данные предварительно загружены и ни один компонент их не использует, они будут удалены через указанное время. Это позволяет балансировать между производительностью и потреблением памяти.

Стратегии предзагрузки

Существует несколько практических стратегий, применяемых в приложениях на RTK Query.

Предзагрузка по событиям интерфейса

Наведение курсора, фокус элемента и появление в области видимости часто используются как триггеры.

onFo cus={() => prefetchUser(id)}

или

onMouseEn ter={() => prefetchUser(id)}

Эти подходы эффективны при высокой вероятности последующего перехода пользователя.

Предзагрузка при рендере списков

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

useEffect(() => {
  items.forEach((item, index) => {
    if (index < 3) {
      prefetchItem(item.id)
    }
  })
}, [items])

Такой подход уменьшает задержку при последовательном просмотре элементов.

Предзагрузка по маршруту

При использовании роутера можно инициировать загрузку данных следующего экрана заранее, до фактического перехода.

const handleNavigate = () => {
  dispatch(api.util.prefetch('getDashboard', undefined))
  navigate('/dashboard')
}

В этом случае экран открывается уже с подготовленными данными.

Инвалидация и взаимодействие с предзагрузкой

Предзагрузка не отменяет механизмы инвалидации. Если тегированные данные были инвалидированы, RTK Query автоматически определит необходимость повторного запроса при следующем использовании.

invalidatesTags: ['Post']

Если данные были предзагружены, но затем инвалидированы, компонент при обращении к useQuery получит обновлённую версию данных.

Поведение при повторных запросах

RTK Query использует дедупликацию запросов. Если предзагрузка уже выполняется или завершена, повторный вызов prefetch с теми же параметрами не инициирует новый запрос, если не указан force: true.

Это особенно важно при массовых событиях, таких как прокрутка списка или массовое наведение курсора на элементы интерфейса.

Оптимизация производительности

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

Практическая оптимизация включает:

  • ограничение числа одновременно предзагружаемых элементов
  • использование onHover вместо onRender для снижения лишних запросов
  • комбинирование с keepUnusedDataFor для управления кэшем
  • выборочную предзагрузку только наиболее вероятных маршрутов

Связь с инкрементальной загрузкой данных

Предзагрузка часто используется вместе с постраничной или ленивой загрузкой. В таких сценариях RTK Query позволяет заранее загружать следующую страницу данных.

dispatch(api.util.prefetch('getPosts', { page: 2 }))

Это создаёт ощущение мгновенной навигации между страницами, так как данные уже находятся в кэше до перехода пользователя.

Поведение при смене параметров запроса

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

  • getPost(1)
  • getPost(2)

Каждый запрос может быть предзагружен отдельно, и данные не пересекаются.

Интеграция с оптимистичными сценариями

Предзагрузка часто комбинируется с оптимистичными обновлениями, где интерфейс заранее предполагает успешный результат операции. В таких случаях предварительно загруженные данные используются как базовая версия состояния, поверх которой применяются изменения.

Такой подход уменьшает визуальные задержки и делает интерфейс более стабильным при работе с сетью с высокой латентностью.