Goal: I would like for my images to load once they get close (happens to be 20% in my example) to the right or bottom of the viewport. I want the user to have the experience that the images "have always been there" as they scroll, i.e. as they're viewing the current image, the image to the right and the image below it are loading off-screen
I tried 2 approaches. I made comments on my approaches in the code and you can easily toggle each approach on and off. With one approach, the right margin behaves correctly, but the bottom margin doesn't. And with the other approach, the opposite happens: the right margin doesn't work correctly, but the bottom margin does.
JavaScript:
import React, {useEffect} from 'react';
import './test.css';
// dummy test data
const coffeeShops = [
{
title: 'Coffee Shop 1',
photos: [
'picture 1 of Coffee Shop 1',
'picture 2 of Coffee Shop 1',
'picture 3 of Coffee Shop 1',
'picture 4 of Coffee Shop 1'
]
},
{
title: 'Coffee Shop 2',
photos: [
'picture 1 of Coffee Shop 2',
'picture 2 of Coffee Shop 2',
'picture 3 of Coffee Shop 2',
'picture 4 of Coffee Shop 2'
]
},
{
title: 'Coffee Shop 3',
photos: [
'picture 1 of Coffee Shop 3',
'picture 2 of Coffee Shop 3',
'picture 3 of Coffee Shop 3',
'picture 4 of Coffee Shop 3'
]
},
{
title: 'Coffee Shop 4',
photos: [
'picture 1 of Coffee Shop 4',
'picture 2 of Coffee Shop 4',
'picture 3 of Coffee Shop 4',
'picture 4 of Coffee Shop 4'
]
}
]
export const Test = () => {
useEffect(() => {
const svgs = document.querySelectorAll('.mySvg');
// I am setting the images to load once they come within 20% of the right or bottom of the viewport.
const rootMargin = '0% 20% 20% 0%';
// Approach 1:
// bottom viewport works!
// right viewport doesn't work: The images load right when they intersect with the right side of the viewport (i.e. 0% instead of the 20% that I set) :(
createObserver(svgs, rootMargin, null);
// Approach 2: (the exact opposite happens)
// bottom viewport doesn't work: If you scroll down you can see that all the images already loaded when the page loaded :(
// right viewport works!
// const scrollContainers = document.querySelectorAll('.scroll-container');
// for (const scrollContainer of scrollContainers) {
// createObserver(svgs, rootMargin, scrollContainer);
// }
}, [])
return (
<>
<div style={{marginBottom: '50px'}}>Awesome Coffee Shops:</div>
{coffeeShops.map(shop => {
return (
<>
<div className='scroll-container'>
{shop.photos.map(photo => {
return (
<svg width='4032' height='3024' className='mySvg'>
<rect x="0" y="0" width='4032' height="3024" stroke='black' fill='white' />
</svg>
);
})}
</div>
<div>{shop.title}</div>
</>
);
})}
</>
);
};
export const createObserver = (svgs, rootMargin, root) => {
const config = {
root,
rootMargin,
threshold: 0
};
const lazyImageObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
const svg = entry.target;
setTimeout(() => svg.childNodes[0].setAttribute('fill', 'purple'), 500); // the setTimeout simulates downloading an image
observer.unobserve(svg);
}
});
}, config);
svgs.forEach(function (svg) {
lazyImageObserver.observe(svg);
});
};
css
.scroll-container {
overflow: auto;
white-space: nowrap;
}
svg {
width: 90%;
height: 90%;
}