Internet is filled with products using infinite scrolling. Infinite scroll makes the consumption of information very easy and highly addictive. Products with timelines or feeds like Twitter, Instagram, etc. are best suited for infinite scrolls.
Implementing the infinite scrolling in JavaScript can be challenging. Especially, when your feed has thousands of items, the problem gets more complex. Let's look at some of the problems.
Problems
- Slow rendering as the browser has to repaint all the elements in case of resizing
- Laggy scrolling
- Finally, thousands of DOM elements on your page can crash the browser
Most devices refresh their screens 60 times a second. Each of those frames has a budget of just over 16ms (1 second / 60 = 16.66ms). When you fail to meet this budget the frame rate drops, and the content shakes on screen. You can check the refresh rate for your webpage using FPS meter available in Chrome. FPS is definitely going to be lower than 60 when you scroll on a page with so many DOM elements.
What can we do?
We'll have to reduce the elements and handle the scroll issues. These are some basic ideas to resolve these issues:
- DOM Recycling: The idea is to render only the visible elements. We can reuse them to render the new items rather than creating new ones.
- Scroll Anchoring: As there will be only 10 elements in DOM, we need to fake the scroll to give the illusion of infinite scroll.
These require a lot of calculations and corner conditions to be managed to implement it efficiently. While reading about the problems I came across react-virtualized package which has built solutions for all these and was recommended by Dan Abramov.
How does react-virtualized work?
React virtualized implements virtual rendering with a set of components that does the same thing:
- They calculate which items are visible inside the area where the list is displayed.
- They use a container with relative position and absolute position the children elements inside of it by changing its width, height, top and left properties.
We are going to use the following components to render a list with dynamic width and items of dynamic width and height:
- List: This component renders a list of elements. It takes care of virtualizing the list and rendering only visible items.
- CellMeasurer: It automatically measures a cell's contents by temporarily rendering it in a way that is not visible to the user. Specify a fixed width to measure the dynamic height (or vice versa).
-
CellMeasurerCache: It stores
CellMeasurer
measurements and shares them with the parent (List
). - AutoSizer: It is a high-order component that automatically adjusts the width and height of a single child.
- InfiniteLoader: It manages just-in-time fetching of data as a user scrolls up or down in a list. It also caches the list data to avoid fetching it again while the user is scrolling.
Let's use them to build a real list.
You can go through the docs to understand the working of these components and the meaning of the different props available.
Caching Issues
If you are re-rendering the list based on some state changes, you might face issues because of the caching done by CellMeasurerCache
and InfiniteLoader
. The cache can be cleared using in-built methods.
// Reset cached measurements for all cells.
this.cellMeasurerCache.clearAll();
// Reset any cached data about already-loaded rows
this.infiniteLoaderRef.resetLoadMoreRowsCache();
Conclusion
I hope this helped you in understanding the problems with implementing large lists and how to deal with them. It provides a basic understanding of react-virtualized package. The package provides lots of other components to solve problems of large and dynamic tables, grids, etc. Brian Vaughn also recommends react-window as a possible light-weight alternative.
Share your use cases and issues you have faced with infinite lists in the comments. Thanks!
Top comments (2)
Hello!
Thank you for your article!
I’m a junior developer, and i have a little, simple question:
How to change the value of stopIndex in fetchFeed function ? =)
I am making an application with a large list of users (more than 2000 users).
It’s my first project with React&Redux, I have little experience and i need some help in this question.
Thank you in advance.
Looking forward to trying this out. Thanks Akshay! :)