React-Virtualized
Overview
Given that React is made to manage data as a state, working with data in it is comparatively simple. When you have to deal with a huge amount of data, managing data can be difficult. Take into account the situation where you need to manage a dataset with 500–1,000 records. Massive loads and performance issues may occur from this. We're going to examine how virtualized lists in React may be used to effectively present a lengthy list of data in your application. For this, we'll make use of the React Virtualized component.
What is Virtualization?
Virtualization in React refers to the technique of using JavaScript to create and manipulate a virtual representation of a component, rather than directly rendering it to the DOM (Document Object Model). This can improve the performance of a React application, especially when dealing with large lists or tables.
Virtualized components only render the items that are visible on the screen, rather than rendering all items at once, which can greatly reduce the amount of work the browser needs to do and improve the overall responsiveness of the application.
Consider rendering a huge list of tweets that are generated every minute. You use HTML, CSS, and JavaScript to retrieve a large quantity of data (likely in JSON), and then you add it to the DOM.
Before the data changes, we might not be able to see all tweets in under a minute. Additionally, there is a possibility that our browser would lose speed and performance because rendering DOM elements use up memory in the browser. So what can we do to ensure that even when we display massive data lists, our browser is lightning fast?
Instead of adding all DOM elements at once, UI virtualization, a front-end concept, directs us to render only the data that is visible in the user's viewport.
The user might have to wait a few seconds when scrolling for the next batch of data to become available in the DOM if we render the same amount of data visible in the user's viewport.
We can fetch extra buffer data to take the user's scroll behaviour into account itoprevent this kind of user experience. This algorithm makes sure that when rendering and reading massive data lists, our browser and users are satisfied.
Now that we have a better understanding of UI virtualization, we can explore how to use it in react.
The Problem
Let's begin by building a React application:
This program will display a list of 1,000 comments like this:
cd into your app directory and install the lorem-ipsum library, which will produce the placeholder text:
Now import lorem-ipsum into src/App.js:
Let's do the following to generate an array with a thousand elements:
The code above will produce an array of 1000 objects, each with the following properties:
- id
- Name
- image
- And a phrase that is four to eight words long.
In this manner, the array can be used by the render() method as follows:
Making the layout of each row using the method renderRow():
Now, if you modify src/App.css to include some CSS styles:
You should see something similar to this after starting the app using npm: Using the Elements panel of the developer tools in your browser, you can examine the page. You would find thousand of div nodes in the DOM and it shouldn't come as a surprise:
Two issues may result from the DOM having so many elements:
- Slow initial rendering
- Slow scrolling
That is not ideal. This may cause the user interface to freeze or even crash on less powerful devices or those with more complicated layouts. Then, how can we effectively display these 1000 rows?
One way to fix this is by using a library called react-virtualized, which employs a method called virtual rendering.
How Does React-Virtualized Work?
The fundamental idea underlying virtual rendering is to only render what can be seen. The app contains 1,000 comments, but it only displays around ten at a time until you scroll to display more. Therefore, it makes logical to only load the visible elements and to unload them by switching them with new ones when they are not visible.
React-virtualized enables virtual rendering using a collection of elements that essentially operate as follows:
- They determine which items are visible inside the list's display area (the viewport).
- By manipulating its top, left, width, and height style values, they use a container (div) with relative placement to the absolute position of the children's components inside of it.
There are Five Key Components
- Grid: It displays data in tabular form along the horizontal and vertical axes.
- List: It internally uses a Grid component to render a list of components.
- Table: It creates a table with a scrollable vertical body and a fixed header. Additionally, a Grid component is used internally.
- Masonry: It displays user-positioned, dynamically scaled cells with the capability for vertical scrolling.
- Collection: It displays data that is randomly positioned and overlapped.
These components simply compare the references when comparing objects since they extend from React.PureComponent, which improves efficiency.
React-virtualized, on the other hand, also includes several HOC elements:
- ArrowKeyStepper: For another component to react to arrow-key events, it is decorated.
- AutoSizer: It automatically modifies another component's width and height.
- CellMeasurer: By momentarily presenting a cell in a way that is hidden from the user, it automatically calculates the contents of that cell.
- ColumnSizer: Column widths for Grid cells are computed.
- InfiniteLoader: As a user scrolls through a List, Table, or Grid, it controls the data-fetching process.
- MultiGrid: Adding fixed columns and/or rows to a Grid component decorates it.
- ScrollSync: The scrolling of two or more components is synchronized.
- WindowScroller: It makes it possible to scroll a Table or List component using the scroll locations of the window.
Let's now examine how to virtualize the example of the 1,000 comments using the List component.
Virtualizing a List
Import the List component from react-virtualizer into src/App.js first:
Now, instead of presenting the list as follows:
Let's render the list in a virtualized manner using the List component:
Notice two points:
- You must first specify the list's width and height in the List component. In order to determine which rows will be visible, it also needs to know the height of the rows. The row height property accepts either a function that returns the height of a row given its index or a set row height.
- Second, the component requires the length of the list (the number of rows) as well as a function to render each row. It doesn't just take the list.
The renderRow method's implementation must be changed as a result. An object from the list will no longer be accepted as an argument for this method. Instead, an object with the following characteristics will be passed to it by the List component:
- Index
- Key
- Style
- Parent
- isVisible
- isscrolling
The renderRow method will now appear as follows:
Take note of how the elements in the list that corresponds to the row being rendered may be accessed using the index attribute.
When you launch the application, you'll see something similar:
Explanation
The rows are now contained within two extra div elements, as can be seen by looking at the page's elements in the developer tools tab:
This time, there are not a thousand elements, and all the rows are the inner div element's children. There aren't either eight or nine elements, though. There are maybe ten more. This is so that the List component can draw more elements and lessen the likelihood of flickering from rapid scrolling.
Autoresizing a Virtualized List
Autoresizing a virtualized list in React refers to the process of automatically adjusting the size of a virtualized list based on the available space and the number of items to be displayed.
As child components, components like AutoSizer follow a pattern referred to as function. As the name suggests, you must pass a function rather than a component as a child. In our example, the one which receives the calculated width and height
The code will then return the List component with the specified width and height:
The AutoSizer component will completely fill its parent's space. If you wish to fill the space following the header, add the following code to the list class in src/App.css:
Explanation
100vh is equal to 100% of the viewport's height since the vh unit measures the viewport's height (the size of the browser window). Due to the header's size (200px) and the padding that the list class adds, 210px are deducted (10px).
Now, If you try to resize the window, the list height should automatically adjust.
Syncing Scrolling between two Lists
To sync scrolling between two virtualized lists in React, we can use the react-virtualized-scrolling library.
To implement it, we need to follow the given steps:
- Install the library: npm install react-virtualized-scrollsync or yarn add react-virtualized-scrollsync.
- Wrap each of the virtualized lists with the ScrollSync component from the library.
- Pass the scrollTop value from the first list to the second list using the scrollTop prop.
- In the second list, set the scroll position using the scrollTop prop.
Here's an example code:
Explanation
With this setup, when you scroll one of the virtualized lists, the other list will automatically scroll to the same position. The ScrollSync component provides a scrollTop value that you can pass as a prop to both lists, and it will keep them in sync.
Ensure Your Large Lists Render Properly
To ensure large lists render properly in React with Redux, you can follow these steps:
- Optimize your list rendering: Use techniques like lazy loading or pagination to render only the visible elements.
- Monitor the state: Use tools like the React Developer Tools browser extension to monitor the state and check for performance issues such as excessive re-renders.
- Track state changes: Use the Redux DevTools extension to track state changes and determine if the state is being updated unnecessarily.
- Profile and debug: Use performance profiling tools like the React Performance DevTools to identify areas of your application that are slowing down and debug performance issues.
By monitoring and tracking the state of your Redux store, you can ensure your large lists render smoothly and efficiently in React.
Some Tips While Using React-Virtualized
Here are some tips for using react-virtualized effectively in a React application:
- Use the appropriate component for the specific use case. For example, use List for a long list of items and Table for a grid with many columns.
- Pass a unique key prop to each item in the list to improve performance.
- Use the estimatedRowSize and estimatedColumnSize props to provide the virtualized component with an estimate of the average size of a row or column, which can help improve performance.
- Be mindful of the overflow prop, which controls how the virtualized component handles items that do not fit within the specified dimensions.
- Use the onScroll prop to handle scrolling events and update the state of your component as needed.
- Use the width and height props to specify the dimensions of the virtualized component.
- Use the rowHeight and columnWidth props to specify the dimensions of the rows and columns.
Conclusion
- React Virtualized is a library that helps to optimize the performance of large lists in React applications by only rendering the visible elements.
- It achieves this by using a technique called "window rendering", where only the items that are currently visible within the viewport are rendered.
- This can significantly improve the performance of a list with a large number of items, as it reduces the amount of work the browser has to do.
- It also improves the scrolling experience by reducing the lag caused by rendering a large number of items at once.
- React Virtualized also provides several other useful features, such as handling scrolling, dynamic item heights, and more.
- React Virtualized can be used with both client-side and server-side rendering.
- Using virtualized lists can be a bit more complex than using a regular list but it can be worth it if you have a very large number of items to be displayed.