4
\$\begingroup\$

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>
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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-like object, that is, an object that is accessed by index and with a length propertie(which is identified as images on our javascript)
  • the second argument will be the mapFunction(which will be imgGenerator), 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);

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.