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.
- 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.
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.
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
CellMeasurermeasurements and shares them with the parent (
- 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.
If you are re-rendering the list based on some state changes, you might face issues because of the caching done by
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();
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!