Загрузить данные проще, чем поддерживать их актуальность

Бесконечная прокрутка кажется довольно простой задачей: загружаем первую страницу, пользователь прокручивает список, подгружаем следующую.

Но ситуация становится интереснее, когда данные начинают изменяться.

Представим интерфейс со списками заявок, разделённых по статусам: новые, в работе и завершённые.

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

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

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

Для решения подобных задач я использовал RTK Query, объединив несколько механизмов.

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

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

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

2. Объединение страниц через merge Новые данные добавляются к уже загруженным. Но обычной конкатенации недостаточно: нужно учитывать повторяющиеся идентификаторы, обновление существующих элементов и ситуации, когда список необходимо загрузить заново.

Особенно важно учитывать, что состав данных на сервере может измениться между запросами.

3. Инвалидация через теги Когда заявка изменяется, необходимо определить, какие кэшированные выборки могли устареть.

Теги RTK Query позволяют помечать связанные кэшированные данные как устаревшие. При наличии активных подписок это обычно приводит к повторным запросам, а не к сбросу всего API-кэша.

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

4. IntersectionObserver и кастомный хук За отслеживание приближения пользователя к концу списка отвечает IntersectionObserver.

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

Но самый интересный момент во всей архитектуре – изменение данных между запросами.

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

Например, при offset-пагинации изменение состава данных на сервере может сдвинуть позиции элементов. В результате следующая страница потенциально принесёт дубликаты или приведёт к пропуску записей.

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

Кстати, сейчас в RTK Query есть отдельный API для бесконечных запросов – infiniteQuery, который берёт на себя часть управления страницами. Описанный подход с serializeQueryArgs и merge позволяет самостоятельно контролировать структуру кэша и объединение данных, но требует внимательного отношения к этим нюансам.

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

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

А как вы решаете синхронизацию Infinite Scroll после изменения данных? Обновляете кэш вручную или предпочитаете инвалидацию и повторную загрузку?

На иллюстрации ниже – абстрактная схема взаимодействия списков, RTK Query и API.

Загрузить данные проще, чем поддерживать их актуальность | Сетка — социальная сеть от hh.ru Загрузить данные проще, чем поддерживать их актуальность | Сетка — социальная сеть от hh.ru