Better Programming

Advice for programmers.

Follow publication

5 Ways to Lazy Load React Components

Obed Mbroh Amoasi
Better Programming
Published in
6 min readFeb 2, 2022

--

Photo by Kate Stone Matheson on Unsplash

Usually, when I look at Figma and XD designs they look longer than its wide, oh I mean they are mostly portrait.

But that’s fine, we all do not expect the whole design to appear on the screen at the same time, we understand that, part of the design will be on the screen and part of the design will be available as the user scrolls.

Awesome. So we wear our goggles and start implementing the designs pixel by pixel. The question is: If we fundamentally are aware that the design will not be visible on the screen at the same time, why then do we bother the browser to render it all at once? Can’t we find a nice way of telling the browser to render only the upcoming component.

How dare the footer, compete for resources with the header when the page is loaded, chances are if you look at your website stats, or usage heat map, there aren’t as many hits to the footer anyway.

The goal here is to give priority to components and elements that are critical to the UX at a particular time. And thankfully React has some awesome API and pointers for us to optimize just that.

Let’s start with images.

Images are just resource intensive, usually, they make a huge portion go the resources that is being served too a page. The problem is, not all images are actually needed. Take for example a slide show, the most important image is the one currently available.

Why then should all the images be given the same priority when requesting the resource from the server?

Let's consider another case where the image isn’t available in the viewport, again, these images shouldn’t be given as many priorities as the images in the viewport.

Lastly, if we take a step back, you may realize, sometimes, even the images in the view port shouldn’t block, nor prevent the site from loading other content, such as the CSS, and some core JavaScript.

My go-to is to defer all images as long as the page can be fine without the image, I say, let’s defer the loading of the image till other components are loaded. You can then load the images in the background or when they come into the viewport.

Let's look at a few ways we can do this.

1. Native support loading=‘lazy’

From MDN docs

Lazy loading is a strategy to identify resources as non-blocking (non-critical) and load these only when needed. It’s a way to shorten the length of the critical rendering path, which translates into reduced page load times.

Very often, webpages contain many images that contribute to data-usage and how fast a page can load. Most of those images are off-screen (non-critical), requiring user interaction (an example being scroll) in order to view them.

All we have to do is to add loading=“lazy” to the image as such


<img src=”image.jpg” alt=”…” loading=”lazy”>

This works amazingly, it will load and render the image as it comes into view and not treat it as a critical resources. Unfortunately, its not supported by all browsers as a result, its recommended to add polypill.

2. Intersection Observer API

Another way to do this is to use the intersection observer API.

Mozilla web documentation describes the intersection observer API as:

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport.

The Intersection Observer API lets code register a callback function that is executed whenever an element they wish to monitor enters or exits another element (or the viewport), or when the amount by which the two intersect changes by a requested amount. This way, sites no longer need to do anything on the main thread to watch for this kind of element intersection, and the browser is free to optimize the management of intersections as it sees fit.

We will first attach an empty src to our image, and when it is in view we will attach our src, the browser will then fetch the src, and it will be a win win for all.

3. Using Libraries

There are other libraries out there that can help with this in the JavaScript ecosystem, and some specific to react.
I will list them here but not go into details of how to use them, as they all have a similar concept of what we have discussed here.

Unfortunately the non-react-based might change the DOM directly so you may want to avoid them.

Actually, you can create an image component, and lazy load it using React.lazy() and React.suspense(). Let's look at these two next.

4. Lazy loading components

Now with the concept of lazy loading images out of the way, we can extend it to other components, again, why do some computations and animations when the element hasn’t appeared in the view. You should again defer loading non critical components. You can achieve this with the inbuilt React.Lazy, React.Suspense and dynamic imports.

This is react’s approach to easily code split your code. According to the docs

Code-splitting your app can help you “lazy-load” just the things that are currently needed by the user, which can dramatically improve the performance of your app. While you haven’t reduced the overall amount of code in your app, you’ve avoided loading code that the user may never need, and reduced the amount of code needed during the initial load.

Let’s consider an About page, we may want to show some articles and a newsletter beneath the actual about content.

The about page may be huge with some images, but as we learned from above, e managed to defer the images, but we are still not super cool with the size of the page.

We can decide to split the newsletter, and the articles from the about page to reduce the size of the initial load. Let's see how we can achieve that here:

Let's go through what’s happening here.

import(“./NewPost”) — This tells the bundler we want to code split here and not add it to the bundle.

const Posts = React.lazy(() => import(“./Posts”)); — This creates a usable component, which we can add to our Jsx as if its a component. But to add it, we will wrap it in the Suspense component, so we can specify a fallback, which should be rendered as long as our component hasn’t completed fetching. You can show your awesome loader here. And just like that, and we will be good to go.

5. Virtualize huge tables

We all understand that it's a bad user experience to show a user a huge list so we agree to paginate or load them infinitely.

Pagination is great, as it means we will only load a sizeable amount of data from the server to show the user at a particular time. But whatever we do, there might be times even the paginated list might not fit on the screen. This is where I believe virtualized list shines.

I first found the concept of virtual lists from Android. On mobile we do not have much resources, so we cant be using memory anyhow The RecyclerView only had a few containers that the data could be rendered in. And when the view gets into the screen, it uses one of the existing containers to render the element, when it is scrolled out of the screen, the container is recycled back, and the data detached, to be reused again.

So if the list can show only 9 things at a time, no matter how many elements you give it to show on the screen, it will use just 9 containers, and be looping through it. We can use a similar concept in React with the help of react-window.

Lemme explain a few props here:

  • The itemKey is a function that gets the required key for your item to be rendered. It will use the index if not passed.
  • The height and width are the dimensions of the container (Table).
  • ItemSize is the height if vertical and width if horizontal of the item to be rendered

You can check out the react window docs here. There are other ways of implementing this, but I find the react-window library a bit easy and straightforward to start with. You can check out this post by Google or Check out how @moshe_31114 built his.

If you want to check out how you can prevent multiple rendering in react, check out my article here. This is part of my series of articles focusing on optimizing the React front end.

Thanks for reading.

--

--

Obed Mbroh Amoasi
Obed Mbroh Amoasi

Written by Obed Mbroh Amoasi

Full Stack Engineer building scalable products handling over a million requests per day. Reactjs | NextJS | Node JS | ReactNative | GCP | AWS | Cloud | Mongo

No responses yet

Write a response