Бесконечная прокрутка — это эффект, который мы накладываем на веб-сайты, чтобы сделать их удобными для пользователя. Этот эффект не является волшебством, это просто умное использование JavaScript, чтобы улучшить общее впечатление от веб-сайта.

Этот метод используется на многих веб-сайтах, особенно с фидом, например. YouTube.

Так как же работает эта штука?

Давайте обсудим основную идею бесконечной прокрутки.

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

Так что же на самом деле здесь происходит?

Для бесконечной прокрутки мы предпочитаем API с включенной разбивкой на страницы. Итак, сначала мы просто запрашиваем первую страницу из API. Теперь, когда пользователь достигает конца страницы, выполняется новый вызов API с номером следующей страницы.

Как вы могли заметить из абзаца выше, мы делаем вызов API, когда доходим до конца страницы. Есть два способа определить конец страницы. Либо страница полностью прокручена, либо последний элемент полностью виден на экране. В этой статье мы узнаем, как именно это сделать.

Мы обсудим два метода реализации Infinite Scroll

Предпосылки

  • Знание React Hook: useState, useRef, useEffect
  • Базовая настройка реагирующего приложения

Реализация — №1

В этом методе мы будем использовать разные значения окон, предоставляемые браузером.

Нам нужно прикрепить прослушиватель событий прокрутки к окну. Это будет сделано внутри useEffect, потому что прослушиватель должен быть подключен, как только компонент будет смонтирован.

useEffect(() => 
  { window.addEventListener("scroll",handleInfiniteScroll); 

  return () => window.removeEventListener("scroll", handleInfiniteScroll);
},[]

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

Попробуйте удалить метод очистки (возврат) в useEffect и запустите код. Затем внимательно следите за тем, как делаются запросы.

Давайте определим метод handleInfiniteScroll

//states
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(true);

//method
const handleInfiniteScroll = async () => {
    try {
      if (
        window.innerHeight + window.document.documentElement.scrollTop + 1 >=
        window.document.documentElement.scrollHeight
      ) {
        setLoading(true);
        setPage((prev) => prev + 1);
      }
    } catch (error) {
      console.error(error);
    }
  };

Мы объявили здесь два состояния, page отслеживает номер страницы, потому что наш API поддерживает разбиение на страницы, поэтому нам нужно передать ему номер страницы.

В методе handleInfiniteScroll мы проверяем условие, что сумма window.innerHeight и window.document.documentElement.scrollTop + дополнительное количество пикселей больше, чем равно window.document.scrollHeight.

window.innerHeight: возвращает внутреннюю высоту окна в пикселях
window.document.documentElement.scrollTop: возвращает количество пикселей при вертикальной прокрутке
window.document.documentElement.scrollHeight: возвращает общую высоту содержимого (которое еще не видно на экране)

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

Этот метод внесет изменения в состояние страницы. Поэтому мы добавим useEffect, который будет вызывать наш API.

//state
const [card, setCard] = useState([])

//method
const getCardData = async () => {
    const res = await fetch(
      `https://jsonplaceholder.typicode.com/posts?_limit=9&_page=${page}`
    );
    const data = await res.json();
    //solved: the first page is repeated twice
    if (page !== 1) {
      setCard((prev) => [...prev, ...data]);
    } else {
      setCard([...data]);
    }
    setLoading(false);
  };

//useEffect
useEffect(() => {
  getCardData();
}, [page]);

Этот фрагмент кода действительно прост. Все, что мы здесь сделали, называется API и сохранили данные в setCard() (вероятно, не самое удачное имя 😅)

Теперь, когда у нас есть все настройки основного кода, мы можем просто передать наши данные, которые находятся в card, компоненту, который будет отображать элементы.

И ВОТ ЭТО!!

Там вы получите бесконечный свиток.

Вот живая демонстрация приложения, которое я создал: https://effortless-granita-f1a33d.netlify.app/

А получить код можно здесь: https://github.com/theshubhagrwl/infinite-scroll-react-window

Реализация — №2

В этом… давайте продолжим, это следующая статья.

Чтобы дать вам подсказку, во втором подходе мы будем использовать IntersectionObserver API

Добрый день!

Первоначально опубликовано на https://blog.theshubhagrwl.in.