Как реализовать пагинацию?
Продвинутые темы
Пагинацию реализуют разбиением данных на страницы: offset-based (page/limit), cursor-based (по курсору) или бесконечный скролл. Сервер отдаёт часть данных и метаданные.
Способы пагинации
Offset-based (страницы)
Классический подход через page/limit (или offset/limit):
GET /users?page=2&limit=20{ "data": [...], "meta": { "total": 100, "page": 2, "limit": 20 } }- Плюсы: просто, можно прыгать на любую страницу.
- Минусы: на больших смещениях медленно (
OFFSETв БД дорог); при вставке/удалении элементы «сдвигаются» (дубли/пропуски).
Cursor-based (курсор)
Отдаём указатель на последний элемент; следующая порция — «после» него:
GET /users?cursor=eyJpZCI6MTAwfQ&limit=20- Плюсы: стабильно при изменениях данных, быстро на больших объёмах.
- Минусы: нельзя прыгнуть на произвольную страницу.
Бесконечный скролл
UI-паттерн: подгрузка следующей порции при приближении к концу (через IntersectionObserver), обычно поверх cursor/offset.
Реализация на клиенте
const { data } = await fetch(`/users?page=${page}&limit=${limit}`).then((r) => r.json());
// показать данные, обновить page, кнопки "далее/назад" или подгрузкаTanStack Query упрощает (useInfiniteQuery).
Как выбирать
- Нужны номера страниц, небольшие данные → offset.
- Большие/меняющиеся данные, лента → cursor + бесконечный скролл.
Коротко для собеседования
Пагинация: offset-based (page/limit — просто, но дорого на больших смещениях и «плывёт» при изменениях), cursor-based (по указателю — стабильно и быстро, но без прыжков на страницу), бесконечный скролл (UI поверх них через IntersectionObserver). Для лент — cursor, для таблиц со страницами — offset.