React - Load API content as elements become visible to users

TL;DR; You can reduce the number of queries you make on listing pages by loading content as it gets displayed. Use react-intersection-observer to detect when an element becomes visible and react-content-loader to display a contentful placeholder loader.

You have a developed your backend API and built your React SPA but you find that some pages actually make a lot of requests (either large or lots) to your backend and have become kind of sluggish. Well good news everyone, you can improve that.

Let's consider a typical layout for a "listing" page. What matters here is not the design but the architecture of the page. You have a list of items and then for each item a list of children. All of these must be dynamically loaded from your API.

A standard listing page layout

What are the traditional approaches?

  1. One big query: You make one fat API query to your backend to load the items and their children (e.g. comments). It works, is perfectly valid for a small number of items but is merely scalable if you expect a high number of children. The biggest problem is being in control of the pagination for the children, which is merely possible when you include children in the parent query. Even with GraphQL, which allows you to paginate children, you would redo the parent query for each new page - this is not optimal.
  2. One query per item: You load items - or item IDs - using a listing query then for each item you load the item body (if not loaded as part of the first query) and the children. This approach is scalable and gives you better control over pagination.

Option 2 is more fluid in terms of architecture. The problem is you'll end up doing quite a lot of queries on page load depending on the number of items you wish to display on the initial page load. Loading 100 items means you'll end up doing N x 100 queries on your API, where N is the number of correlated resources you need to load for each item.

Considering most of the items will be below the fold, it seems like a huge waste of resources to load everything on page load. A better approach would be to load items as they become visible to users.

Let's do just that.

The useInView hook to the rescue

The react-intersection-observer library provides a hook detecting when an element becomes visible to users.

It has plenty of configuration options - such as configuring a percentage threshold of object height for when to trigger the inView event - but we'll go with the most basic implementation here.

Add react-intersection-observer to your project:

Now you can use the inView hook on your page items to conditionally load related children:

That's it. You've just saved your backend hundreds of queries potentially.

The useInView hook will guarantee that your API queries are only executed if your element actually becomes visible to the user.

Now we've considerably increased the number of components that will be in a loading state as the user scrolls your page. Therefore let's make that loading state nice and contentful.

Contentful placeholder loader

The react-content-loader loader library allows you to define pulsing SVG objects to be used as a placeholder while your content is loading.

I find this approach nicer than the traditional spinners as it gives your users an indication of what to expect in terms of layout once your content is loaded.

Here is an example of a comment placeholder loader:

Example of comment loader

The nicest thing about this library is that the author actually developed a site to help you design these SVG loaders. Just go to https://skeletonreact.com and get fancy!

Now let's incorporate that placeholder into our component.

First install the library in your project:

Then design your component on https://skeletonreact.com and add it to your project:

Finally conditionally display your loader in your comment feed component:

That's it!

Your comment feeds now load dynamically as users scroll your page and a nice placeholder loader lets them know it's coming!

About us

Keypup is on a mission to help developers and tech leads work better with each others on development projects. Our platform automatically centralizes, prioritizes and assigns people and actions on issues and pull requests to optimize your development flow.

Don't get lost because you have to juggle with twenty pull requests across five development projects. We'll clean and organize that for you to ensure a smooth landing.

---

Code snippets hosted with ❤ by GitHub

Don't miss these stories: