Rendering large lists, The Right Way!

Pravesh Vyas
Engineering at Prodigal
3 min readJul 27, 2022

After working with User Interfaces (UI), you might have noticed that rendering long lists takes a lot of time, then you are not alone.

We were using React, a UI library that takes the Re-rendering Components approach based on state changes, which is done by diffing the current State of DOM with React’s Representation of the Same with updated changes called Virtual DOM.

We encountered a similar issue in one of our products while trying to render captions of long calls. Our first instinct was to try out React’s inbuilt memoization inside a Scrollable list. The implementation was successful but not up to the mark. It did not feel right: all our overlays and controls were lagging.

Here’s the closest example we could replicate:

Normal list lagging on Scroll.
Normal List

If you want to try out this example, here is the Code Sandbox (CSB). Try at your own risk! It can break your CSB. Link to the above code

Before proceeding further, here are a few assumptions and the reasoning behind them.

In the sandbox linked above, A list state has been set to generate an array of 10k items. also, a time state updating every 100 milliseconds, on each list render we are simulating processing by adding a “for” loop of 10k iteration, it does nothing to the UI. But it adds good enough complexity to represent, any complex operation we want to on every render on each List Element.

The core issues with this approach were the uneasy lag on scrolling the list. The update frequency is not so fast and sets us up for a bad user experience.

Now that we have some context on the problem, let’s look at how to approach an optimal solution. The concept of windowing is used in various ways to solve complex problems. If index tracking is done for all the currently visible items and renders only those indexes, it saves a lot of processing on the thread. This means that the length of the list won’t be connected to the time needed to render the list on UI.

In a virtual list, rendering time is not related to the length of the list.

https://twitter.com/addyosmani/status/1104645563138506753
Virtual List

You might have noticed that we are using a GIF to display the first example and using a Sandbox to display the second. Embedding such a heavy sandbox causes issues. When using a virtual list, everything runs smoothly. Let’s see how we make that happen.

How do we do this?

The bare minimum for such an implementation requires tracking currently visible indexes and rendering only those indexes. There are readily available solutions that ease the implementation process, without reinventing the wheel. Some of these solutions include react-virtualized and react-window.

Here is the implementation using React virtualized, which is functionally similar to one in the Normal list

Let’s see how this library works:

  1. Auto sizer: Defines the size of the List based on parent component properties
  2. List: It is React virtualized implementation of a List that internally works as a grid
  3. rowCount: It is the length of the list.
  4. rowRender: It is the callback function that gets index, styles, key, and other properties as a parameter and returns a JSX element that represents the row that is being rendered, and data is accessed with the help of the index
  5. rowHeight: Defines the height of each row.

Conclusion

The concept of windowing is helpful in delivering a lag-free experience to the users and boosting the performance of the Application. It helps in implementing a buttery smooth solution without stressing too much load on the client browser.

For a deep dive visit https://www.patterns.dev/posts/virtual-lists/

Image — https://twitter.com/addyosmani/status/1104645563138506753

--

--