Гид по технологиям

Бесконечная прокрутка в React.js

6 min read Frontend Обновлено 11 Apr 2026
Бесконечная прокрутка в React.js — руководство
Бесконечная прокрутка в React.js — руководство

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

Коротко о термине

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

Реализация бесконечной прокрутки в React.js

Существует несколько подходов:

  • Использовать готовую библиотеку (например, react-infinite-scroll-component). Она упрощает логику, но добавляет зависимость.
  • Использовать встроенные методы React (lifecycle или хуки) и обработчик события scroll.
  • Использовать IntersectionObserver для более точного и энергоэффективного отслеживания «подхода к концу» дом-элемента.

Ниже — перевод и адаптация примеров, советы по лучшим практикам, критерии приёмки и чек-листы для разработчиков, QA и менеджеров.

Использование react-infinite-scroll-component

Установка

Чтобы начать, установите пакет через npm:

npm install react-infinite-scroll-component --save

Импорт и пример класса

После установки импортируйте компонент в свой React-компонент.

import React from 'react'  
import InfiniteScroll from 'react-infinite-scroll-component'  
  
class App extends React.Component {  
  constructor() {  
    super()  
    this.state = {  
      items: [],  
      hasMore: true  
    }  
  }  
  
  componentDidMount() {  
    this.fetchData(1)  
  }  
  
  fetchData = (page) => {  
    const newItems = []  
  
    for (let i = 0; i < 100; i++) {  
      newItems.push(i )  
    }  
  
    if (page === 100) {  
      this.setState({ hasMore: false })  
    }  
  
    this.setState({ items: [...this.state.items, ...newItems] })  
  }  
  
  render() {  
    return (  
      

Infinite Scroll

Loading...} endMessage={

Yay! You have seen it all

} > {this.state.items.map((item, index) => (
{item}
))}
) } } export default App

Этот пример создаёт state с пустым массивом items и флагом hasMore. Метод fetchData генерирует dummy-данные и добавляет их в состояние. Когда достигнут последний «страничный» номер, флаг hasMore переводится в false, и компонент перестаёт запрашивать новые данные.

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

  • dataLength — длина массива данных. Компонент использует это значение, чтобы понять, что появились новые элементы.
  • next — функция, вызываемая для подгрузки следующей порции данных.
  • hasMore — флаг, указывающий, есть ли ещё данные.
  • loader — элемент-индикатор загрузки.
  • endMessage — сообщение при достижении конца.

Важно: в реальном приложении fetchData должен делать сетевой запрос к API, обрабатывать ошибки и показывать индикатор загрузки.

Скриншот React-приложения с бесконечной прокруткой и внешней библиотекой

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

Можно реализовать бесконечную прокрутку с помощью хуков useState и useEffect, а также обработчика scroll.

import React, {useState, useEffect} from 'react'  
  
function App() {  
  const [items, setItems] = useState([])  
  const [hasMore, setHasMore] = useState(true)  
  const [page, setPage] = useState(1)  
  
  useEffect(() => {  
    fetchData(page)  
  }, [page])  
  
  const fetchData = (page) => {  
    const newItems = []  
  
    for (let i = 0; i < 100; i++) {  
      newItems.push(i)  
    }  
  
    if (page === 100) {  
      setHasMore(false)  
    }  
  
    setItems([...items, ...newItems])  
  }  
  
  const onScroll = () => {  
    const scrollTop = document.documentElement.scrollTop  
    const scrollHeight = document.documentElement.scrollHeight  
    const clientHeight = document.documentElement.clientHeight  
  
    if (scrollTop + clientHeight >= scrollHeight) {  
      setPage(page + 1)  
    }  
  }  
  
  useEffect(() => {  
    window.addEventListener('scroll', onScroll)  
    return () => window.removeEventListener('scroll', onScroll)  
  }, [items])  
  
  return (  
    
{items.map((item, index) => (
{item}
))}
) } export default App

Этот подход прост, но у него есть недостатки: слушатель scroll может срабатывать очень часто и нагружать основной поток. Используйте debounce/throttle, чтобы снизить частоту вызовов, и не забывайте отписываться от событий.

Экран React-приложения с бесконечной прокруткой, реализованной встроенными средствами

IntersectionObserver: современный и эффективный способ

IntersectionObserver отслеживает пересечение DOM-элемента с viewport и работает более экономно, чем глобальный обработчик scroll. Подойдёт для загрузки следующей пачки элементов, когда «сентинел» (нижний маркер) появляется в зоне видимости.

Пример с хуками:

import React, { useRef, useState, useEffect } from 'react'

function InfiniteWithObserver({ loadMore }) {
  const [items, setItems] = useState([])
  const [page, setPage] = useState(1)
  const [hasMore, setHasMore] = useState(true)
  const sentinelRef = useRef(null)

  useEffect(() => {
    // загрузка первой страницы
    loadPage(page)
  }, [])

  useEffect(() => {
    if (!sentinelRef.current) return
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting && hasMore) {
          setPage(p => p + 1)
        }
      })
    })
    observer.observe(sentinelRef.current)
    return () => observer.disconnect()
  }, [hasMore])

  useEffect(() => {
    if (page === 1) return
    loadPage(page)
  }, [page])

  function loadPage(p) {
    // loadMore должен возвращать Promise с массивом элементов
    loadMore(p).then(newItems => {
      if (!newItems || newItems.length === 0) setHasMore(false)
      setItems(prev => [...prev, ...newItems])
    }).catch(() => setHasMore(false))
  }

  return (
    
{items.map((it, i) =>
{it}
)} {hasMore &&
}
) } export default InfiniteWithObserver

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

Плюсы и минусы бесконечной прокрутки

Плюсы:

  • Плавное взаимодействие и ощущение «безостановочного» просмотра.
  • Меньше кликов и перезагрузок страниц.
  • Хорошо подходит для лент, соцсетей и галерей.

Минусы:

  • Потеря ориентации: пользователи могут не понять, где нашли конкретную запись.
  • Сложности с закладками и прямыми ссылками на элементы далеко вниз в ленте.
  • Проблемы с SEO и индексированием (поисковым ботам может быть сложнее просмотреть весь контент).
  • Рост потребления памяти в браузере при отсутствии виртуализации.

Важно: комбинируйте бесконечную прокрутку с возможностью поиска, фильтрации и «показать ещё» для сохранения контроля.

Когда бесконечная прокрутка не подходит

  • Если пользователи ожидают явную навигацию по страницам (например, каталоги товаров с чёткими страницами и URL).
  • Когда важна возможность ссылаться на конкретное место в списке.
  • Если требуется строгая SEO-оптимизация для каждой порции контента.

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

Альтернативы и гибриды

  • Кнопка «Показать ещё» — простая и предсказуемая альтернатива. Пользователь контролирует загрузку.
  • Пагинация — даёт стабильные URL и предсказуемость; подходит для каталогов товаров.
  • Гибрид: бесконечная прокрутка внутри страницы результатов с возможностью «загрузить всё».

Лучшие практики и эвристики

  • Загружайте данные порциями (page size) и отдавайте пользователю индикатор загрузки.
  • Используйте debounce/throttle для обработчиков scroll.
  • При большом количестве элементов применяйте виртуализацию (react-window, react-virtualized).
  • Сохраняйте позицию прокрутки при навигации назад (history state или session storage).
  • Добавьте явную кнопку «Наверх» и «Показать ещё» для мобильных пользователей.
  • Обрабатывайте ошибки сети и показывайте повторную попытку.

Доступность (A11y) и SEO

  • Для доступности: обеспечьте фокусируемые элементы, доступные метки и возможность клавиатурной навигации.
  • Экранные читалки: уведомляйте пользователя о динамически добавленных элементах с помощью aria-live.
  • SEO: если контент важен для индексации, обеспечьте доступ к нему через пагинацию, sitemap или серверный рендеринг (SSR). Также можно использовать «progressive enhancement»: базовая пагинация + динамическая подгрузка для улучшенного UX.

Важно: не полагайтесь только на клиентский JavaScript для контента, который должен индексироваться.

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

  • Виртуализация: держите в DOM только видимые элементы.
  • Lazy-loading изображений и медиаконтента.
  • Кэширование страниц и результатов API.
  • Ограничивайте объём данных в каждом запросе и используйте сжатие (gzip/brotli).
  • Следите за утечками памяти: удаляйте обработчики и референсы.

Критерии приёмки

  • Стандартный сценарий: при прокрутке вниз подгружается следующая порция данных без дублирования и потерь.
  • Граница: при достижении конца списка отображается корректное сообщение «конец».
  • Ошибки сети: при сбое показывается уведомление и кнопка «Повторить».
  • Доступность: aria-live уведомляет о добавлении контента; клавиатурная навигация не ломается.
  • Производительность: FPS не падает заметно при прокрутке; память контролируется.

Чек-листы ролей

Разработчик:

  • Реализовать подгрузку и обработку ошибок.
  • Добавить debounce/IntersectionObserver.
  • Реализовать виртуализацию при большом списке.
  • Сохранить позицию при навигации.

QA:

  • Проверить сценарии подгрузки, дублирование и конец списка.
  • Проверить восстановление после ошибки сети.
  • Проверить доступность с клавиатуры и screen reader.

Продуктовый менеджер:

  • Утвердить, где нужен infinite scroll, а где — пагинация.
  • Определить допустимый latency и размер порций.
  • Принять критерии приёмки.

План отката (инцидентный runbook)

  1. Зафиксировать время и симптомы (много дублированных элементов, утечки памяти, падения).
  2. Откатить фронтенд к версии без бесконечной прокрутки или с выключенным feature flag.
  3. Если причины на бэкенде — откатить API или лимитировать объём отдаваемых данных.
  4. Включить глубокое логирование и мониторинг (метрики latency, error rate, memory).
  5. Провести постмортем и исправить root cause.

Тестирование: тест-кейсы и приёмка

  • TC1: Подгрузка следующей страницы при прокрутке до низа.
  • TC2: Обработка пустой страницы (hasMore=false).
  • TC3: Повторная попытка при ошибке сети.
  • TC4: Нормальное поведение при очень медленном соединении.
  • TC5: Виртуализация: проверка, что в DOM не держатся все элементы.

Сравнение: бесконечная прокрутка vs пагинация

КритерийБесконечная прокруткаПагинация
UX для лентыОтличный — плавный просмотрМенее плавный, но предсказуемый
Ссылка на конкретный элементСложноЛегко (URL)
SEOТребует доработокХорошо индексируется
Контроль пользователяМеньше контроляБольше контроля
РеализацияСредняя сложностьПростая

Методика внедрения (микро-план)

  1. Прототип: реализуйте на отдельном фиче‑брэнче с feature flag.
  2. Тестирование: функциональные и нагрузочные тесты.
  3. Релиз в Canary: ограничьте процент пользователей.
  4. Мониторинг: latency, errors, memory, engagement.
  5. Раскатка: при стабильности — включение для всех.

Резюме

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

Важно: в критичных с точки зрения SEO и навигации местах отдавайте приоритет пагинации или комбинируйте подходы.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро