Ленивая загрузка - одна из тех тем, которые никогда не устареют, я впервые увидел их еще во времена jQuery. В любом случае, по мере развития javascript и появления новых парадигм и фреймворков, мы, конечно же, должны обновить наш новый способ делать старые вещи.

Некоторое время назад я искал решение для реализации отложенной загрузки изображений в React. Первое, с чем я столкнулся, был пакет response-lazyload. Это хорошо, но всегда лучше, если вы сначала реализуете свою собственную версию, по крайней мере, для небольших и быстрых задач, подобных этой, потому что, на мой взгляд, количество новых вещей, которые вы узнаете, выполняя это самостоятельно, более ценно, чем время, которое вы сэкономите на просто npm-установка.

Еще кое-что перед тем, как приступить к программированию; использование C Loudinary здесь, конечно, необязательно. Я использую его, потому что он позволяет вам применять фильтры (например, размытие, которое мы будем использовать) и запрашивать изображения разных размеров на лету. Больше никаких разговоров!

Итак, ключевая идея здесь: иметь тег-заполнитель <img />, который всегда скрыт, так как его src, он имеет ссылку на фактическое (высококачественное) изображение, когда оно загружается, оно вызывает функцию, чтобы сказать, что оно готово, в этот момент свойство isLoaded из state обновляется, и контейнер <div> изменит свой backgroung-image с размытого низкого качества (высота: 10 пикселей в моем случае ~ 1 КБ) на загруженное изображение высокого качества (строка 52) .

Но это была идея до добавления наблюдателей пересечений, хотя, поступая таким образом, мы будем загружать все изображения на странице, когда компонент будет установлен. В игру вступает Intersection Observer, позволяющий нам загружать изображения, когда они начинают входить в область просмотра, позвольте мне показать вам, как: когда компонент установлен, мы создаем нового наблюдателя для нашего <div>. конструктор Intersection Observer принимает два аргумента, первый обратный вызов для вызова , когда процент пересечения между целевым элементом и его предком больше или равен нашему пороговому значению (цель может иметь любую форму, но для при вычислении пересечения будет считаться наименьший прямоугольник, который его включает) . и, во-вторых, варианты (строка 15). root - это предок, с которым вы хотите сравнить эту цель, null означает просто использовать область просмотра браузера. rootMargin - это просто поле, которое вы хотите вокруг своего корня, с помощью rootMargin вы можете в некотором смысле увеличивать или уменьшать область просмотра, например, установив rootMargin : "100% 0%", мы попросим наблюдателя начать вычисление пересечение, когда цель находится на100% высоты области просмотра от верхнего и нижнего краев области просмотра. И threshold может быть либо одним значением, либо массивом значений (воспринимайте их как проценты), при которых будет вызван обратный вызов. Поэтому, если вы хотите получать уведомления, когда ваш компонент пересекает область просмотра на 25%, 50% и 75%, вы можете просто установитьthreshold : [0.25, 0.5, 0.75]. Затем в строке 22 мы начинаем наблюдать за нашим componentobserver.observe(target).

После того, как мы настроили наблюдателя для нашего маленького компонента, в строке 25 мы определяем для него нашу функцию обратного вызова. Обратный вызов принимает два аргумента: записи (все элементы-наблюдатели, которые достигли своего порогового значения) и, во-вторых, сам объект наблюдатель. Поэтому, когда компонент установлен, мы начинаем наблюдать, есть ли какие-либо элементы, удовлетворяющие нашим условиям (строка 27, один важный момент здесь заключается в том, что не гарантируется, что значение, которое вы получаете в intersectionRatio, точно соответствует вашему порогу значение, вы должны думать о пороге как о минимальном значении). Если это так, в нашем intersectionObserverCallback мы перебираем их и обновляем состояние, устанавливая для isLoaded значение true. Это приведет к удалению тега <img />, и фон нашего <div> изменится, а затем, поскольку изображение загружено, мы можем безопасно удалить наблюдателя, и мы сделаем это с помощью observer.unobserve(target).

В функции рендеринга я проверяю, достаточно ли виден компонент, чтобы начать загрузку высококачественного изображения, или нет, тогда будет добавлен тег <img />, а когда он будет готов, он будет удален. В album-cover-container я просто добавил простую анимацию типа transition : all 0.3s ease-in;, чтобы добиться эффекта плавного появления. Кроме того, есть две небольшие вспомогательные функции, которые говорят сами за себя, поэтому я не буду о них говорить.

И последнее, чтобы заставить Intersection Observer работать во всех браузерах, я использовал полифилл пересечения-наблюдателя. Я просто импортирую его перед любым другим модулем, чтобы он мог проверить объект window перед выполнением кода моего компонента.

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

Be aware that your callback is executed on the main thread. It should operate as quickly as possible

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