Vastly improve the performance of your React apps using (React.lazy() and Suspense)

Lazy loading💤 has come to be one of the optimization techniques widely used now to speed up the load time. The prospect of Lazy Loading helps reduce the risk of some of the web app performance problems to a minimal〽.

In this article, we will look into how to use lazy loading💤 to optimize load time in our React apps.

What’s Lazy Loading💤?

Lazy loading is an optimization trick💫 whereby we delay the load of an object(image🎦, video🎬, webpage🌎, music file🎶, documents📋) until when it is needed.

When a user opens a webpage, all the contents are downloaded in one fell swoop. Most of the contents may never be interacted with or seen by the user. So why waste precious resources and bandwidth?

To boost the response time of our site, we defer the loading of some non-critical parts of our app at load time. These resources are then loaded when the user accesses part of the page that requires it.

SSR, CSR and React

We have SSR(server-side rendered) apps and CSR(Client side rendered) apps.

SSR is the good old web pages built with .HTML and inlined with ASP.NEt, PHP. Each link has a different .HTML file to load

web-app/
 - index.html
 - about.html
 - faq.html
 - careers.html

Each page has a different HTML file.

As JS frameworks emerged, the web pages are mashed up into a single js and loaded in one fell swoop. Upon execution in the browser, the requested page is generated by the browser DOM.

In React, let’s say we have an app like this:

// index.js
export default () =>(<Switch>
    <Route path='/about' component={About} />
    <Route path='/faq' component = {FAQ} />
    <Route path='/careers' component = {Careers} />
</Switch>)// about.js
class About extends Component{
    render() {
        return (<div>About page</div>)
    }
}// faq.js
class FAQ extends Component{
    render() {
        return (<div>FAQ page</div>)
    }
}// careers.js
class Careers extends Component{
    render() {
        return (<div>Careers page</div>)
    }
}

On bundling, webpack packs all the js files into one index.js

react-app/
 dist/
  - index.html
  - index.js

All files index.js, about.js, faq.js, careers.js was bundled into one file. Now, when we load the index.html file it drags along the heavily-laden index.js with it. Now, the time⏰ taken to parse through all the codes in the index.js and rendering will be a long wait. If the time taken for each js file to execute is as follows:

  • index.js 2ms
  • about.js 10ms
  • faq.js 5ms
  • careers.js 9ms

Bundled:

  • index.js 26ms

Therefore we will wait for 26ms!! But if we could separate the files in React and load them on demand, we will see that it will take our app 2ms to load and respond.

So instead of downloading the entire code, we can split the bundle into small chunks and dynamically load them at runtime.

So many techniques have been used to code-split React apps. We see them in the next sections.

⏬Dynamic Import

To code-split, our JS apps, the import() function was introduced. It’s still a proposal, not yet part of JavaScript standard.

This function makes it possible to split our apps into chunks and load them on demand.

The import() takes a string as a parameter. The string is the path of the js file to load.

import('./js_file_to_load.js')

When webpack comes across this, it bundles the file in the path separately.

💤React.lazy()

React.lazy is a new feature added to React when Reactv16.6 was released, it offered an easy and straight-forward approach to lazy-loading and code-splitting our React components.

The React.lazy function lets you render a dynamic import as a regular component. — React blog

React.lazy makes it easy to create components and render them using dynamic imports. React.lazy takes a function as a parameter:

React.lazy(()=>{})// orfunction cb () {}
React.lazy(cb)

This callback function must load the component’s file using the dynamic import() syntax:

// MyComponent.js
class MyComponent extends Component{
    render() {
        return (<div>MyComponent</div>)
    }
}const MyComponent = React.lazy(()=>import('./MyComponent.js'))
function AppComponent() {
    return (<div><MyComponent /></div>)
}
// orfunction cb () {
    return import('./MyComponent.js')
}
const MyComponent = React.lazy(cb)
function AppComponent() {
    return (<div><MyComponent /></div>)
}

The callback function of the React.lazy returns a Promise via the import() call. The Promise resolves if the module loads successfully and rejects if there was an error in loading the module, due to network failure, wrong path resolution, no file found, etc.

When webpack walks through our code to compile and bundle, it creates a separate bundle when it hits the React.lazy()and import(). Our app will become like this:

react-app
 dist/
  - index.html
  - main.b1234.js (contains Appcomponent and bootstrap code)
  - mycomponent.bc4567.js (contains MyComponent)/** index.html **/
<head>
    <div id="root"></div>
    <script src="main.b1234.js"></script>
</head>

Now, our app is now separated into multiple bundles. When AppComponent gets rendered the mycomponent.bc4567.js file is loaded and the containing MyComponent is displayed on the DOM.

🚦React Suspense

Now, what happens when the file mycomponent.bc4567.js gets loaded, there must be a time lag from when it loaded to when the MyComponent it contains is rendered. What will the user see?

Apparently, your app will seem to freeze for some time. That will be a bad user experience. We need to let the user know that something is happening or loading. In order to do that a new feature associated to React.lazy was added it is the Suspensecomponent.

The Suspense component is used to wrap lazy components to show some fallback content while loading the lazy components.

const Lazycomponent = React.lazy(()=>import('./lazy.component.js'))function AppComponent() {
    return (
    <div>
        <Suspense fallback={<div>loading ...</div>}>
            <LazyComponent />
        </Suspense>
    </div>)
}

The component that is being lazily loaded is inserted inside the Suspense component tags. The content to show to the user to tell them that something is going on is placed in the fallback prop of the Suspense component tag.

Components can also be used in the fallback prop:

// ...
function LoadingIndicator () {
    return (<div>loading ...</div>)
}function AppComponent() {
    return 
    (<div>
        <Suspense fallback={<LoadingIndicator />}>
            <LazyComponent />
        </Suspense>
    </div>)
}

Multiple lazy components can be placed in the Suspense tag.

const Lazycomponent1 = React.lazy(()=>import('./lazy.component1.js'))
const Lazycomponent2 = React.lazy(()=>import('./lazy.component2.js'))
const Lazycomponent3 = React.lazy(()=>import('./lazy.component3.js'))
const Lazycomponent4 = React.lazy(()=>import('./lazy.component4.js'))function AppComponent() {
    return 
    (<div>
        <Suspense fallback={<div>loading ...</div>}>
            <LazyComponent1 />
            <LazyComponent2 />
            <LazyComponent3 />
            <LazyComponent4 />
        </Suspense>
    </div>)
}

#react #javascript #programming #web-development #developer

Improve The Performance of React App with React.lazy and Suspense
1.75 GEEK