lbry-desktop/ui/effects/use-lazy-loading.js
infinite-persistence afe4fee3f3 Fallback image for <FileThumbnail>
## Ticket
5457 Create file thumbnail fallback image for odysee

## Approach
Since `background-image` does not invoke an `onerror` event, create a test Image instance to have the `onerror` capability. This technique is used by majority of plugins. No additional fetch is seen with this technique.
2021-08-17 19:46:54 -07:00

77 lines
2.3 KiB
JavaScript

// @flow
import type { ElementRef } from 'react';
import React, { useEffect } from 'react';
/**
* Helper React hook for lazy loading images
* @param elementRef - A React useRef instance to the element to lazy load.
* @param backgroundFallback
* @param yOffsetPx - Number of pixels from the viewport to start loading.
* @param {Array<>} [deps=[]] - The dependencies this lazy-load is reliant on.
*/
export default function useLazyLoading(
elementRef: { current: ?ElementRef<any> },
backgroundFallback: string = '',
yOffsetPx: number = 500,
deps: Array<any> = []
) {
const [srcLoaded, setSrcLoaded] = React.useState(false);
const threshold = 0.01;
function calcRootMargin(value) {
const devicePixelRatio = window.devicePixelRatio || 1.0;
if (devicePixelRatio < 1.0) {
return Math.ceil(value / devicePixelRatio);
}
return Math.ceil(value * devicePixelRatio);
}
useEffect(() => {
if (!elementRef.current) {
return;
}
const lazyLoadingObserver = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.intersectionRatio >= threshold) {
const { target } = entry;
observer.unobserve(target);
// useful for lazy loading img tags
if (target.dataset.src) {
// $FlowFixMe
target.src = target.dataset.src;
setSrcLoaded(true);
// No fallback handling here (clients have access to 'onerror' on the image ref).
return;
}
// useful for lazy loading background images on divs
if (target.dataset.backgroundImage) {
if (backgroundFallback) {
const tmpImage = new Image();
tmpImage.onerror = () => {
target.style.backgroundImage = `url(${backgroundFallback})`;
};
tmpImage.src = target.dataset.backgroundImage;
}
target.style.backgroundImage = `url(${target.dataset.backgroundImage})`;
}
}
});
},
{
root: null,
rootMargin: `0px 0px ${calcRootMargin(yOffsetPx)}px 0px`,
threshold: [threshold],
}
);
// $FlowFixMe
lazyLoadingObserver.observe(elementRef.current);
}, deps);
return srcLoaded;
}