Как сделать такую проверку скролла на React?

на сайте идут секции друг под другом К примеру как на картинке( их больше 3 )

введите сюда описание изображения

Пользователь скроллит, доходит до начало 1 секции И когда секция полностью заходит в экран( т.е верхний угол секции находится на верху экрана) добавляется класс к примеру active ( для самой секции ) И так по аналогии со 2 секции

Я предоставляю себе реализацию таким образом. Проходимся по всем секциями и записываем их координаты. А когда пользователь скроллит добавляем проверку если к примеру scroll > элемента из массива , секции с данным индексом добавить класс. Правда саму реализации в коде не предоставляю. Спасибо заранее


Ответы (3 шт):

Автор решения: Dan

Получилось сделать примерно так, только вопрос, не будет ли это слишком нагружено ?

useEffect(() => {
    window.addEventListener('scroll', function (event){
      setScroll(window.scrollY > bannerPosition);
      if (window.scrollY < positions[0]) return;
      const index = positions.findIndex((el, i, arr) => window.scrollY < arr[i + 1]);

      const categoryAttribute = "[data-id=" + "'" + index + "'" + "]";
      const element = document.querySelector(categoryAttribute)

      const allElements = document.querySelectorAll('.menu-nav li span')
      for(let el of allElements){
        el.classList.remove('active')
      }

      if(element) element.classList.add('active')
      if(index === -1 && window.scrollY > positions[0]){
        allElements[allElements.length - 1].classList.add('active')
      }
    })

  },[bannerPosition, positions])
→ Ссылка
Автор решения: Серега Мангышев

Вы можете наблюдать за элементом при помощи технологии. IntersectionObserver
Они очень быстрые, так как работают внутри DOM.

Если выражаться простым языком, своего рода это событие, которое выполняется, если искомый элемент в зоне поражения.

Вы можете сами указать угол обзора и учитывать отступы или нет, так же изначально он ищет в body, вы можете менять и это. Изучите технологию пожалуйста!

→ Ссылка
Автор решения: Ruslan Donchenko

Чтобы не было сильно загружено, нужно перенести это в кастомный хук.

const useКастомныйХук = (если нужны параметры через запятую, deps) => {
  useEffect(() => {
    содержимое useEffect
  }, [...deps]);
  //если нужно можно что-нибудь вернуть
  return {
    ...
  };
};

export default useКастомныйХук;

//Теперь этот хук можно использовать в компоненте так:

const SomeComponent = (props) => {

  useКастомныйХук(
    параметры, если нужно через запятую,
    [bannerPosition, positions]
  );

  return (
    ...
  );
};
→ Ссылка