Back in , Do you know what a virtual list is? I introduced the question about virtual lists. Here we will do some exploring.

If you read the post and are still unsure, this post will help you grasp the concept even further.

When you are visiting Twitter, you are most of the time only viewing several tweets at a time. As you know, you can scroll up or down to see more. How many tweets do you think are in your feed? Infinite? Kind of.

Diagram of what twitter looks like
What it is like viewing twitter

As you can see above, we only see several tweets at a time. If Twitter was naïve, in how they implemented their application, you would have endless amounts of tweets in a given timeline. This would make the application crash or be extremely slow. Imagine how much memory it would cause the browser to handle infinites amounts of tweets!

Not only would this be bad for performance, but really, wasteful. Other than allowing your users to scroll through tweets, we are wasting a lot of memory on things the user cannot see in the viewport. Also, now imagine that you want to animate the tweets, or something else! It would be a bad time.

The issue we are solving

  • Allow users to scroll an infinite list of tweets
  • Allow number of tweets in the list to not affect performance

What should we do first?

We need a way to only render to the screen tweets that a user could possibly see at a given moment, and remove everything else. We can start to understand how we will get there by dissecting how we might calculate what is on the page.

First we will need to have a way to calculate how many tweets can fit in a page:



Since we are dealing with a vertical list, we should find the height of the viewport the user has. If we are using a browser, we could use the window.innerHeight API.

Second, we would want to find the height of each item in the list, so we can calculate how many items will fit within a viewport.

const howManyCanFit = (viewportHeight, itemHeight) =>  viewportHeight / itemHeight;

Using a function like above, we can calculate how many we should be showing at a time. Easy, right? Not quite. We need more information than this.

We also need to know the position of the page we are on so we show the right items, not just the right amount of items. This is where it will get a little more tricky.

We want to understand viewportHeight, itemHeight, scrollTop (scroll position of viewport), and itemCount (number of items we need to calculate "tweets").

export function getVisibleItemIndexes(
  containerHeight: number,
  rowHeight: number,
  numberOfItems: number,
  _scrollTop: number
): number[] {
  const itemIndexes = [];
  const itemHeight = rowHeight;
  const itemCount = numberOfItems;
  const scrollTop = _scrollTop;
  let itemScrollTop = 0;

If we are able to find all of this information, we can use it to get back a list of items that should be visible based on scroll position and height of the viewport.

For each item, we will calculate when it can become visible, so we know ahead of time, before the user scrolls, which items in our list should be shown.

for (let index = 0; index < itemCount; index += 1) {

Now we will calculate the scrollTop of the item we are on in this loop. Basically we want to know when the top of an item could be in view.

itemScrollTop = index * itemHeight - scrollTop;

We check if the item is below the viewport and skip it if true

if (itemScrollTop >= containerHeight) {
  continue;
}

Then check if the item is above the viewport and also skip if true

 if (itemScrollTop + itemHeight <= 0) {
   continue;
 }

If neither of the above, we want to add it to our "visible items"

  itemIndexes.push(index);
}

Then return the results

  return itemIndexes;
}

Given the right parameters, we would get a list back of the indexes of items that should be rendered

[0, 1, 2, 3]

Ok that is it for today. Next we will see this work in action, and continue to learn how to solve this problem. Hope you enjoy!

Want to know when the next post drops? Subscribe to our newsletter -->