React — Deep Understand How Lazy Load Works on React Component

Didik Mulyadi
6 min readSep 25, 2022
Photo by Artem Sapegin on Unsplash

There’s a problem in our project regarding the heavy component. When I open that app it will show the blank screen first or there’s a blink when moving to a different page.

What we want are:

  1. no blank screen in the initial load
  2. no blinking screen when the user moves to another page.

Problems

So let's see the exam results and how to solve

1. Component too big

When I check the component, the source code is too big. there are 1 thousand lines of code 😭 in one component.

It means:

  • All initial APIs are called at the same time, there’s nothing API Call Priority.
  • The bundle size result is not good because there’s a possibility the reusable component not implemented

My personal opinion, the maximum line of code is 800 lines. Mostly code will be hard to maintenance when reach > 800 lines

Example Component A

2. All components loaded at the same time

Even though we are already splitting the code, it just splitting the bundle files in the browser. but it still loaded at the same time.

Solution

1. Splitting component -> Make it reusable

When we do a split component, the advantages that we got are:

  • Easier for maintenance
  • Easier for reading the code
  • Easier to add a lazy load
  • Reduce a bundle size

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.

When we have split our components, we are ready for a lazy load! 🚀

2. Add lazy load in Routes

React.lazy currently only supports default exports.

So makesure, you use “export default”

to add lazy load just convert your import from this

import BigComponent from "./pages/BigComponent";
import SplittingComponent from "./pages/SplittingComponent";

to this

import React, { lazy } from "react";const BigComponent = lazy(() => import("./pages/BigComponent"));
const SplittingComponent = lazy(() => import("./pages/SplittingComponent"));

It is just a solution, but how it works? let's talk and see how to react lazy load improves your app 🚀

How Lazy Load Works

Basically, When a component uses a lazy load. that component will be fetched at a different time (not in the initial load) and will be stored in a different file, not in the main bundle bundle.js , that file called *.chunk.js.

if you add a lazy load for a component inside a page directory, there will be a chunk file with pages_**.chunk.js.

See how lazy load improves your app below! 🚀

Codebase

  1. I use a sample project from my repository
    https://github.com/didikmulyadi/medium-react/blob/main/react-cra-vite branch “lazy-load”
  2. That project contains:
    - 70 files inside /components (a component with the same code) to increase default bundle size (there are 15 lines)
    - 6 pages (a big component that has the same code)
    - 2 pages (a component that uses lazy load and not uses lazy load)
  3. BigComponent is a component that contains more than 1000 lines
    SplittingComponent is a component that called many components with lazy load lazy(() => import("..."))
    SplittingComponentNoLazyLoad is a file that called many components without lazy load import ABC from "..."
<Routes>
<Route path="/" element={<BigComponent />} />
<Route path="/big-component-2" element={<BigComponent2 />}
<Route path="/big-component-3" element={<BigComponent3 />} />
<Route path="/big-component-4" element={<BigComponent4 />} />.
<Route path="/big-component-5" element={<BigComponent5 />} />.
<Route path="/big-component-6" element={<BigComponent6 />} />.
<Route path="/splitting-component-lazy-load"
element={<SplittingComponent />}
/>
<Route path="/splitting-component-no-lazy-load"
element={<SplittingComponentNoLazyLoad />}
/>
</Routes>

No Lazy Load on Route Level

I use a root path “/”

See the network when we do not use the lazy load in the route

Browser Network without Lazy Load in Router

There is:
- bundle file bundle.js, which contains all of your components (compressed: 439 kB, real: 2.8 MB).

A size in the network is compressed size, if you are trying to download bundle.js the size will be 2.8 MB

1 kB is 1000 bytes (Decimali.e. 10^3 is kilo)
1 KB/KiB is 1024 bytes (Binary i.e. 2^10)

Imagine your project has many pages and components, and how KB is needed to load your website in the initial load.

What we want is to load something that we want in the initial load.

Lazy Load on Route Level

I use a root path “/” with lazy load import. This implementation for Single Page Application (SPA)

See the network when we use the lazy load in the route, the difference is there’s a chunk file.

Browser Network with Lazy Load in Router

There’s
- bundle.js (compressed: 406 kB, real: 1.9 MB)
-
src_pages_BigComponent_tsx.chunk.js (compressed: 8.2 kB, real: 137 KB )

A size in the network is compressed size, if you are trying to download bundle.js the size will be 1.9 MB

1 kB is 1000 bytes (Decimali.e. 10^3 is kilo)
1 KB/KiB is 1024 bytes (Binary i.e. 2^10)

So, what happened here is bundle.js only contains the main bundle for the web app and the additional file will be fetched after the main bundle is already fetched (see the “Waterfall” column in the image above)

With this, we don’t worry about having many pages in our single-page application.

No Lazy Load in Component Level

I use a path “/splitting-component-no-lazy-load”. We use lazy load for Route but not for component

See the network when we do not use the lazy load in the route

Browser Network without Component Lazy Load

Because we added lazy load for this route, there’s:
- bundle.js (compressed: 406 kB, real: 1.9 MB)
- a chunk file src_pages_SplittingComponentNoLazyLoad.chunk.js (compressed: 8.0 kB, real: 189 KB)

A size in the network is compressed size, if you are trying to download the chunk file, the size will be 1.9 MB

1 kB is 1000 bytes (Decimali.e. 10^3 is kilo)
1 KB/KiB is 1024 bytes (Binary i.e. 2^10)

All of the components inside that route will be stored in that chunk file. So, if your page has a big component, it will affect your initial page load.

Lazy Load in Component Level

I use a path “/splitting-component-lazy-load”. We use lazy load for Route and component

See the network when we do use the lazy load in the route and component

Browser Network with Component Lazy Load

Because we added lazy load for this route, there’s:
- a chunk file src_pages_SplittingComponentLazyLoad.chunk.js (compressed: 3.3 kB, real: 27 KB)
- a chunk file src_component_ComponentDummy_1_copy_[number].tsx.chunk.js (compressed: 5.2 kB, real: 24 KB)

The size is different when you not using lazy load because another component will be fetched in the different chunk file.

Now, no worries for many pages and many components 🥳

Matrix

To summarize our test above, see this table to see the different more clearly.

A page matrix with lazy load and not use lazy load

Conclusion

Always using a lazy load for a component that is not needed in the first/initial load to prioritize the load of your component.

Thank you for reading!
Reach me: https://www.linkedin.com/in/didikmulyadi/

--

--

Didik Mulyadi

👋 Hi, Just call me "Didik", I'm a software engineer with experience over 5 years. Reach me on Linkedln https://www.linkedin.com/in/didikmulyadi/