Полное руководство по бесконечной прокрутке в React

Бесконечная прокрутка — это паттерн пользовательского интерфейса, при котором новый контент загружается по мере прокрутки страницы пользователем. Распространенный в социальных лентах, хронологиях и новостных приложениях, это удобный способ исследовать большие наборы данных без использования кнопок пагинации. В этом руководстве вы узнаете, как реализовать бесконечную прокрутку в React, используя как стороннюю библиотеку, так и собственный хук.
Ключевые моменты
- Изучите 2 практических способа реализации бесконечной прокрутки в React
- Используйте собственный хук с IntersectionObserver или стороннюю библиотеку
- Управляйте состояниями загрузки, пагинацией и пустыми результатами
Что такое бесконечная прокрутка?
Бесконечная прокрутка загружает новые данные, когда пользователь прокручивает список до конца. Это устраняет необходимость в пагинации и создает непрерывный опыт просмотра. Вы увидите это в таких продуктах, как Instagram, Twitter и Reddit.
Метод 1: Использование пакета (react-infinite-scroll-component
)
Самый простой способ реализовать бесконечную прокрутку в React — использовать хорошо протестированный пакет.
Шаг 1: Установка
npm install react-infinite-scroll-component
Шаг 2: Пример базового использования
import InfiniteScroll from 'react-infinite-scroll-component';
function Feed() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const fetchMoreData = async () => {
const res = await fetch(`/api/posts?page=${page}`);
const newItems = await res.json();
if (newItems.length === 0) setHasMore(false);
else {
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
}
};
return (
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={hasMore}
loader={<h4>Loading...</h4>}
endMessage={<p>No more results</p>}
>
{items.map(item => <div key={item.id}>{item.title}</div>)}
</InfiniteScroll>
);
}
Преимущества
- Быстрая настройка
- Встроенные состояния загрузки и завершения
Недостатки
- Меньше контроля над логикой прокрутки
- Добавляет зависимость от пакета
Метод 2: Собственный хук с IntersectionObserver
Этот метод дает вам полный контроль без дополнительных зависимостей.
Шаг 1: Создание хука
function useInfiniteScroll(callback, ref) {
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) callback();
});
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, [callback, ref]);
}
Шаг 2: Использование в компоненте
function Feed() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const sentinelRef = useRef(null);
const loadMore = async () => {
if (!hasMore) return;
const res = await fetch(`/api/posts?page=${page}`);
const newItems = await res.json();
if (newItems.length === 0) setHasMore(false);
else {
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
}
};
useInfiniteScroll(loadMore, sentinelRef);
return (
<div>
{items.map(item => <div key={item.id}>{item.title}</div>)}
<div ref={sentinelRef} style={{ height: 1 }} />
</div>
);
}
Преимущества
- Полностью настраиваемый
- Работает с любой логикой прокрутки или API
Недостатки
- Требует больше настройки
- IntersectionObserver не поддерживается в IE11
Паттерны и советы для реальных проектов
- Используйте debounce для вызовов fetch, чтобы избежать перегрузки API
- Показывайте спиннер или скелетон-загрузчик для лучшего UX
- Добавьте логику повторных попыток для сетевых ошибок
- Обрабатывайте крайние случаи, такие как нулевые результаты или пустые страницы
if (items.length === 0 && !hasMore) {
return <p>No posts found.</p>;
}
Соображения по производительности
- Используйте библиотеки типа
react-window
для виртуализации при рендеринге тысяч элементов - Мемоизируйте компоненты элементов, чтобы предотвратить повторные рендеры
- Правильно очищайте наблюдатели, чтобы избежать утечек памяти
useEffect(() => {
const observer = new IntersectionObserver(...);
return () => observer.disconnect();
}, []);
Заключение
Бесконечная прокрутка — это распространенная функция в современных пользовательских интерфейсах. Независимо от того, предпочитаете ли вы простоту пакета или контроль собственного хука, React делает оба подхода доступными. Всегда учитывайте производительность и обратную связь при загрузке при реализации бесконечной прокрутки.
Часто задаваемые вопросы
Использование библиотеки, такой как `react-infinite-scroll-component`, обеспечивает быструю и удобную настройку.
Установите флаг `hasMore` в значение false, когда API возвращает пустой массив.
Может, если вы рендерите слишком много элементов. Используйте инструменты виртуализации, такие как `react-window`, для управления большими списками.
Используйте `IntersectionObserver` для запуска загрузки данных, когда нижний `div` (сентинель) попадает в поле зрения.