Современный API браузера для отслеживания видимости элементов и создания эффективных взаимодействий

Проблема

Допустим, мы создаем интерфейсную часть сайта на современном Javascript, возможно, с такой структурой, как React, и мы хотим получать данные из API, когда в поле зрения появляется конкретный элемент или компонент, или мы хотим воспроизвести анимацию, или отслеживать, как долго клиент просматривал определенную часть страницы.

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

Решение

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

Из MDN, вот основы того, как мы можем это настроить.

let options = {
  threshold: .5
}

let observer = new IntersectionObserver(callback, options);

Поскольку мы не указали root в нашем объекте параметров, этот наблюдатель пересечения будет отслеживать, когда его наблюдаемые элементы входят в область просмотра, в данном случае не менее чем на 50%.

Мы назначаем отслеживаемые элементы, вызывая метод observer.observe и передавая целевой узел DOM.

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

const imageContainer = document.querySelector("#bannerImage")
observer.observe(imageContainer)
const callback = (entries, observer) => {
let response = await fetch('./api/endpoint/images')
let data = await response.json()
entries[0].target.src = data.logoUrl
observer.unobserve(entries[0].target)

}

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

Использование IntersectionObserver в React

Теперь, когда мы получили основы, давайте воспользуемся этим в компоненте React. Поскольку API-интерфейс IntersectionObserver должен быть передан в качестве цели DOM, нам нужно будет использовать ловушку useRef.

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

function IntersectContainer() {
let [state, setState] = useState({
visible: false,
ratio: 0
})  
const ref = useRef()

  useEffect(() => {    const observer = new IntersectionObserver(([entry])=> {
setState({
visible: entry.isIntersecting,
ratio: entry.intersectionRatio
})
}), {threshold: [.25, .5, .75, 1]})
  });
if (ref.current) {
observer.observe(ref.current)
}
return () => {
      observer.unobserve(ref.current);
    };
  }, []); 
}
let children = React.Children.map(this.props.children, child => {
      return React.cloneElement(child, {
        isVisible: state.visible,
        ratio: state.ratio
      });
    });

  return (
<div className="intersectionComponent">
    {children}
</div>

  );
}

Здесь мы используемState, чтобы отслеживать, является ли наш элемент видимым, и его соотношение, которое является видимым, и мы используемEffect, чтобы мы должным образом создавали экземпляр наблюдателя и присваивали ему нашу ссылку только тогда, когда этот компонент монтируется, и отключаем ссылку, когда он размонтируется. Кроме того, мы используем React.Children, чтобы иметь возможность передавать реквизиты, касающиеся видимости и соотношения на основе состояния родителя. И последнее замечание: вместо одного порогового значения мы передаем массив, чтобы обратный вызов запускался в каждой из этих точек. Такой вид функциональности может быть полезен, если мы хотим использовать эти ключевые отношения, чтобы определить, когда будут срабатывать ключевые кадры анимации.

Вывод

Хотя IntersectionObserver все еще не поддерживается в IE, он имеет широкую поддержку в современных браузерах и может быть мощным инструментом, особенно при использовании вместе с React Hooks, как мы это сделали сегодня.

Ваше здоровье.

Ресурсы:

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