Maximize User Experience with Infinite Scroll
Tags: react, webdev, ux, javascript
Published: 2021-03-21 04:24:21

# What is Infinite Scroll?

**Infinite Scrolling** is highly trending as an interaction behavior on pages and lists. The basic functionality is that, as the user scrolls through content, more content is loaded automatically. With the popularity of social media, massive amounts of data are being consumed, **Infinite Scrolling** offers an efficient way to browse that ocean of information, without having to wait for pages to preload. Rather, the user enjoys a truly _responsive experience_, whatever device they’re using.

# Demo

{% codepen https://codepen.io/ruppysuppy/pen/abBeZwj %}

# Getting Started

We will be implementing **Infinite Scroll** in a **React** Project. Set up a **React** Project before continuing. 

# Implementing **Infinite Scroll**

First let's add the `Item` component.

```javascript
const Item = ({ children, reference }) => {
  return (
    <div ref={reference}>
      {children}
    </div>
  );
};
```

We need to use `ref` to store the reference to the last element for **Infinite Scroll**.

Creating the `App` component.

```javascript
const MAX_PAGES = 5;

const App = () => {
  const [items, setItems] = React.useState([]);
  const [isLoading, setIsLoading] = React.useState(false);
  const [hasMore, setHasMore] = React.useState(true);
  const [pages, setPages] = React.useState(0);
  const observer = React.useRef();

  React.useEffect(() => {
    // generating the 1st page on Component Mounting
    updateItems();
    setPages((pages) => pages + 1);
  }, []);

  const lastItemRef = React.useCallback(
    (node) => {
      // ensuring redundant calls are not made once the data is already BEING updated
      if (isLoading) return;
      if (observer.current) observer.current.disconnect();

      observer.current = new IntersectionObserver((entries) => {
        if (entries[0].isIntersecting && hasMore) {
          if (pages < MAX_PAGES) {
            // adding more data only if:
            // 1. MORE data exists ("hasMore" - simulated with "pages < MAX_PAGES")
            // 2. the last item is visible on the screen (using the "IntersectionObserver")
            updateItems();
            setPages((pages) => pages + 1);
          } else {
            setHasMore(false);
          }
        }
      });

      if (node) observer.current.observe(node);
    },
    [isLoading, hasMore]
  );

  const updateItems = async () => {
    setIsLoading(true);
    // simulating asynchronous nature of api (which is the general use case for Infinite Scroll)
    await new Promise((resolve) => setTimeout(resolve, 1000));

    setItems((currItems) => {
      const lastItem = currItems.length;
      const updatedItems = [...currItems];
      for (let i = 1; i <= 5; i++) {
        const item = lastItem + i;
        updatedItems.push(item);
      }
      return updatedItems;
    });

    setIsLoading(false);
  };

  return (
    <React.Fragment>
      <h1>Infinite Scroll Demo</h1>
      {items.map((item, index) =>
        index + 1 === items.length ? (
          <Item reference={lastItemRef} key={index}>
            {item}
          </Item>
        ) : (
          <Item key={index}>
            {item}
          </Item>
        )
      )}
      {isLoading && <div className="loader" />}
    </React.Fragment>
  );
};
```

# Update

As pointed out by some people in the comments, it can lead to performance degradation, so its suggested that when using infinite scroll for large list of items (around 250+ items), you should create the following **CSS** class:

```css
.hidden {
    visibility: hidden !important;
}
```

and add it to your items when they are not in the viewport.

# Projects using this Implementation

**Smartsapp** (**Previous Messages** on scroll up)

Web-app: [https://smartsapp-ba40f.firebaseapp.com](https://smartsapp-ba40f.firebaseapp.com/)

{% github https://github.com/ruppysuppy/SmartsApp %}

**Pizza Man** (**Previous Orders** on scroll down)

Web-app: [http://pizza-man-61510.firebaseapp.com/](http://pizza-man-61510.firebaseapp.com/)

{% github https://github.com/ruppysuppy/Pizza-Man %}

Finding **personal finance** too intimidating? Checkout my **Instagram** to become a [**Dollar Ninja**](https://www.instagram.com/the.dollar.ninja/)

# References

### YouTube
  1. [Infinite Scrolling With React - Tutorial (Web Dev Simplified)](https://www.youtube.com/watch?v=NZKUirTtxcg)

### Smashing Magazine
  1. [Infinite Scroll: Let’s Get To The Bottom Of This](https://www.smashingmagazine.com/2013/05/infinite-scrolling-lets-get-to-the-bottom-of-this/)

# Thanks for reading

Reach out to me on:

-   [Portfolio](https://tapajyoti-bose.web.app)
-   [GitHub](https://github.com/ruppysuppy)
-   [LinkedIn](https://www.linkedin.com/in/tapajyoti-bose-429a601a0)