AirNYT: React-Virtualized + Material-UI Cards for Fast Lists

This tutorial will cover how to use React-virtualized with Material-ui Cards and Grid to make a list of image-heavy cards that loads extremely fast. Doing this not only allows for much faster loading and re-rendering (such as when using client-side filters) but also better user experience in general. This tutorial is part of a broader series on building an AirBnb-like interface for exploring New York Times travel recommendations.

We start with this app as our baseline:

Github: https://github.com/kpennell/nytairbnbbucketlist

Demo: http://nytrecsalaairbnb.surge.sh/

The Problem: Hundreds of Image-heavy Cards

This app is loading 400+ image-heavy cards. For fast wifi, this is generally fine. But for slower connections (and/or mobile), this app is going to feel sluggish. If I add client side filters, it will feel even more sluggish. And if someone were to use this for an app with 40000 instead of 400 cards, it would feel extremely sluggish. No one likes that.

Here are some snapshots of from the Chrome console before I ‘fix’ this problem:

The Solution: React-Virtualized

React-Virtualized is an awesome library written and maintained by Brian Vaughn (he works on the React team at Facebook). Brian describes React-Virtualized as a set of components for efficiently rendering large lists and tabular data. He gives a great explanation of the library and why he invented it here:

It is a great talk and the key element is this part about windowing: (https://youtu.be/t4tuhg7b50I?t=670):

Windowing is a technique of only rendering what a user actually sees in their browser. In other words, there’s no need to attach a bunch of list, table, grid items to the DOM that the user is not currently using or seeing. So the problem with my list of cards (in the example app, above) is exactly this: the user’s browser is forced to load a bunch of images that the user might not actually see or be using. Let’s fix this with React-Virtualized.

Implementing React-Virtualized

The current implementation of my Grid of Cards is fairly straightforward:

This maps over the props.locations and renders cards in a nice flex-box grid. Here’s the steps I’ll take to implement this same ui using react-virtualized.

First things first:

Next, I’m going to use React-Virtualized AutoSizer and List components for this grid ui. Autosizer is a “High-order component that automatically adjusts the width and height of a single child”. Put a bit more simply, Autosizer is a component that goes around (as a parent or HOC) a List or Table component to allow it access to the width and height props. These width and height props are useful for making responsive or dynamic lists or tables.

The next component I will use is the List component. The List component is fairly self-explanatory in that it is what React-virtualized uses for ‘windowed’ or ‘virtualized’ lists.

Source: https://bvaughn.github.io/react-virtualized/#/components/List

Here is some code with inlined comments that show how I use AutoSizer and List together to implement my same Card grid.

If you happened to get lost in those comments and lines of code, let me try to simplify this:

We have an <AutoSizer> component. In our example, it calculates the (potentially) changing height and width of the user’s browser window.

Ok, then we have a <List> component. It will create our list. But we need to give it props first. If you check the docs for this component, you’ll see that it needs rowCount, height, rowHeight, rowRenderer, and width. rowRenderer (docs here) is the potentially confusing one. This is the function in charge of ‘creating’ or rendering our rows. But it needs to know which rows to render when. In this example, we give it a key and an index. The index tells the rowRenderer where exactly it is in the collection (be it row 2 or row 1,000,002).

From the docs:

Alrighty, so then we have that for loop in there:

This for loop is creating a smaller array (from the whole big props.locations array) to be rendered within the window. If you’re still not quite getting it, I recommend logging index and items and then scrolling down, like so:

And you should see something like this in the console:

What Did We Win?

What did we achieve with this slightly-confusing code? Let’s check the chrome console again:

The previous implementation had 329 requests and 29MB transferred, which took 8.46s to load:

The React-Virtualized example had 43 requests which transferred 3.6MB and loaded in 3.79s.

Using React-Virtualized allowed us to save a ton of bandwidth and user waiting time. Now if we could just get Soundcloud to do the same!

I hope this helped you understand the key points of using this incredible library. Upcoming tuts will get us back on track to finish up making this AirBnb clone.

Update: Brian Vaughn (the creator of React-Virtualized) submitted a pull request and showed how to do this tutorial using React-Window (a faster version of React-Virtualized): https://github.com/kpennell/nytairbnbbucketlist/commit/101a32bb0555f3a7cc29151de195882b249972e8

That said, here is the code for this tutorial using React- Virtualized: https://github.com/kpennell/nytairbnbwithvirtualized

 

Kyle Pennell
Kyle Pennell is a marketer and writer with a variety of technical chops (JavaScript, Google Sheets/Excel, WordPress, SEO). He loves clear and helpful copy and likes automating things and making web apps (mostly maps). Found at kyleapennall.com and many other digital spaces