I built a simple infinite scroll using the intersection observer API, would love some feedback on ways to improve my JavaScript and make it more maintainable and reusable, and feedback according to best JavaScript practices.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Infinite Scroll</title>
<style>
body {
font-family: sans-serif;
font-size: 16px;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
max-width: 520px;
margin: 0 auto;
}
img {
width: 100%;
height: 100%;
margin: 1rem 2rem;
}
#load-more {
padding: 1rem 2rem;
margin: 2;
background-color: darkcyan;
color: white;
border-radius: 1rem;
}
</style>
</head>
<body>
<div class="container">
<div id="infinite-scroll-imgs-container"></div>
<div id="load-more">Loading more content...</div>
</div>
<script>
const loadMore = document.querySelector("#load-more");
const observer = new IntersectionObserver(handleIntersect, { threshold: 1 });
const imgsContainer = document.querySelector("#infinite-scroll-imgs-container");
observer.observe(loadMore)
function randomInteger() {
return Math.floor(Math.random() * 1000000);
}
function imgGenerator(images) {
const imgs = [];
for (let i = 0; i < images; i += 1) {
const img = document.createElement("img");
img.src = `http://api.adorable.io/avatars/${randomInteger()}`;
img.classList.add('infinite-scroll-img')
imgs.push(img);
}
return imgs;
}
function appendImages(container, images) {
container.append(...imgGenerator(images));
}
function handleIntersect(entries, observer) {
entries.forEach((entry) => {
if (entry.isIntersecting) {
appendImages(imgsContainer, 5);
}
});
}
appendImages(imgsContainer, 5);
</script>
</body>
</html>
1 Answer 1
I think that container and images are being repeated unecessarly.
When you call imgGenerator in appendImages, you already know that you want an array of images.
You can use Array.from:
- the first argument will be an
array-likeobject, that is, an object that is accessed by index and with a length propertie(which is identified asimageson our javascript) - the second argument will be the
mapFunction(which will beimgGenerator), a function that will be called for every item of the array
Doing this, on imgGenerator you avoid to make an instance of an array(imgs), a push into it and a for loop every time you want this array, although, you will not need to pass images as parameter again
the container is always imgsContainer, so, in the appendImages you already know where to append
function imgGenerator() {
const img = document.createElement("img");
img.src = `http://api.adorable.io/avatars/${randomInteger()}`;
img.classList.add('infinite-scroll-img');
return img;
}
function appendImages(images) {
imgsContainer.append(
...Array.from({ length: images }, imgGenerator)
);
}
function handleIntersect(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
appendImages(5);
}
});
}
appendImages(5);