From f7cf21b6616a4ab8f0b98b5edcae15f4de24895e Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 8 Jul 2021 21:17:37 +0800 Subject: [PATCH] useLazyLoading: start loading when near viewport ## Issue #6332 ## Change Switch from "threshold-based check" to "viewport distance comparison" using the `rootMargin` parameter. The root is the viewport. This change makes it closer to the native `loading="lazy"` behavior, where it starts to load when approaching the viewport. Chrome I believe uses 3000px distance -- I think 500px is a good compromise for now. Can adjust further. ## Future - We are currently creating N instances of IntersectionObserver. - https://developers.google.com/web/updates/2016/04/intersectionobserver - "If you need to observe multiple elements, it is both possible and advised to observe multiple elements using the same IntersectionObserver instance by calling observe() multiple times." This would probably need a refactor to make ClaimList (or something higher) own the IntersectionObserver. --- ui/effects/use-lazy-loading.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ui/effects/use-lazy-loading.js b/ui/effects/use-lazy-loading.js index 415bdf168..8e9ed8555 100644 --- a/ui/effects/use-lazy-loading.js +++ b/ui/effects/use-lazy-loading.js @@ -5,15 +5,24 @@ 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 {Number} [threshold=0.5] - The percent visible in order for loading to begin. + * @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 }, - threshold: number = 0.25, + yOffsetPx: number = 500, deps: Array = [] ) { 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) { @@ -45,11 +54,12 @@ export default function useLazyLoading( }, { root: null, - rootMargin: '0px', - threshold, + rootMargin: `0px 0px ${calcRootMargin(yOffsetPx)}px 0px`, + threshold: [threshold], } ); + // $FlowFixMe lazyLoadingObserver.observe(elementRef.current); }, deps);