Pagination через URL

TanStack Router предоставляет мощные возможности для управления состоянием приложения через маршруты, включая синхронизацию параметров пагинации с URL. Это позволяет создавать удобные интерфейсы с поддержкой прямых ссылок на определённые страницы, сохранением состояния при обновлении и глубокими ссылками.


Основные принципы работы с пагинацией

Параметры пагинации обычно включают два элемента: текущую страницу (page) и количество элементов на странице (pageSize). В URL они могут быть представлены как query-параметры:

const route = createRoute({
  path: '/items',
  search: {
    page: { type: 'number', defaultValue: 1 },
    pageSize: { type: 'number', defaultValue: 10 }
  }
});
  • page — номер текущей страницы.
  • pageSize — количество элементов на странице.
  • defaultValue задаёт значение, которое используется, если параметр отсутствует в URL.

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


Получение и изменение состояния пагинации

Для работы с параметрами маршрута TanStack Router предоставляет хуки:

const { search } = useRoute({ route });
const currentPage = search.page;
const currentPageSize = search.pageSize;

Изменение состояния выполняется через функцию navigate или через router.setSearch:

router.setSearch({
  page: currentPage + 1
});

При этом URL автоматически обновляется, что позволяет синхронизировать состояние интерфейса с адресной строкой браузера.


Динамическая загрузка данных

Пагинация обычно связана с запросами к API. Для этого удобно использовать зависимые данные маршрута:

const itemsRoute = createRoute({
  path: '/items',
  search: {
    page: { type: 'number', defaultValue: 1 },
    pageSize: { type: 'number', defaultValue: 10 }
  },
  loader: async ({ search }) => {
    const response = await fetch(`/api/items?page=${search.page}&limit=${search.pageSize}`);
    return response.json();
  }
});
  • loader автоматически получает актуальные значения query-параметров.
  • Возвращённые данные доступны через хук useLoaderData, что упрощает привязку к компоненту.
const items = useLoaderData();

Таким образом, при смене страницы URL обновляется, loader перезапускается, и новые данные подгружаются без лишней логики внутри компонента.


Интеграция с компонентами UI

Для компонентов пагинации необходимо передавать текущие параметры и функцию для изменения страницы:

function Pagination({ page, pageSize, totalItems }) {
  const totalPages = Math.ceil(totalItems / pageSize);

  return (
    <div>
      <button
        disabled={page <= 1}
        onCl ick={() => router.setSearch({ page: page - 1 })}
      >
        Назад
      </button>
      <span>{page} / {totalPages}</span>
      <button
        disabled={page >= totalPages}
        onCl ick={() => router.setSearch({ page: page + 1 })}
      >
        Вперед
      </button>
    </div>
  );
}
  • Состояние страницы управляется через router.setSearch.
  • Кнопки автоматически блокируются на границах диапазона.
  • Компонент не хранит внутреннего состояния, полностью полагаясь на маршрутизатор.

Сохранение состояния фильтров вместе с пагинацией

Часто пагинация используется вместе с фильтрами и сортировкой. TanStack Router позволяет комбинировать их через search-параметры:

const itemsRoute = createRoute({
  path: '/items',
  search: {
    page: { type: 'number', defaultValue: 1 },
    pageSize: { type: 'number', defaultValue: 10 },
    sort: { type: 'string', defaultValue: 'name' },
    filter: { type: 'string', defaultValue: '' }
  }
});

Изменение фильтрации автоматически может сбрасывать страницу на первую:

router.setSearch({
  filter: 'electronics',
  page: 1
});

Такое решение гарантирует, что URL всегда отражает актуальное состояние интерфейса.


Поддержка истории и глубоких ссылок

Использование query-параметров делает возможным:

  • Ссылки на конкретную страницу и фильтр (/items?page=2&filter=electronics).
  • Навигацию назад/вперед через браузер с сохранением состояния.
  • Лёгкую интеграцию с закладками и внешними ссылками.

TanStack Router автоматически синхронизирует изменения search-параметров с историей браузера, что исключает необходимость вручную управлять window.history.


Оптимизация для больших данных

При работе с большим количеством страниц стоит учитывать:

  • Отложенную загрузку данных через loader или React Query.
  • Кэширование страниц, чтобы повторные переходы не требовали запроса к серверу.
  • Постраничное отображение ссылок, ограничивая количество видимых кнопок, например, показывая ±2 страницы вокруг текущей.
const visiblePages = Array.from({ length: 5 }, (_, i) =>
  Math.min(Math.max(page - 2 + i, 1), totalPages)
);

Итоговый паттерн работы

  1. Создать маршрут с query-параметрами page и pageSize.
  2. Использовать loader для динамической загрузки данных.
  3. Управлять пагинацией через router.setSearch.
  4. Комбинировать с фильтрами и сортировкой.
  5. Синхронизировать состояние с URL для поддержки глубоких ссылок.

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