DEV Community

Cover image for How to Lazy-Load Your React App
Shittu Olumide
Shittu Olumide

Posted on • Updated on

How to Lazy-Load Your React App

In this article we are going to discuss how we can improve the performance of our apps by loading only the JavaScript that the user needs at any point in time, reducing the amount of code they have to download and execute on page load, and making the app interactive faster.😎 Cool Isn't it?

We’ll use React.lazy and Suspense to delay the loading of a complex component like KendoReact’s StockChart until a button is clicked.

Understanding Dynamic Imports

Instead of sending a big bundle with all the code for our app on initial page load, we can send smaller bundles gradually as the user interacts with the app. To do this we’ll rely on a modern JavaScript feature called dynamic imports. A dynamic import returns a promise that will resolve once the required module gets transferred over the network, and is parsed and executed by the JavaScript engine.

A static import looks like this:

import { concat } from "./utils";

console.log(concat("A", "B", "C"));
Enter fullscreen mode Exit fullscreen mode

While a dynamic import looks like this:

import("./utils").then(utils => {
  console.log(utils.concat("A", "B", "C"));
});
Enter fullscreen mode Exit fullscreen mode

Tools like Create React App and webpack understand what we’re trying to do with these dynamic imports, and will output separate JavaScript files for these lazy-loaded bundles. If we’re configuring webpack ourselves, it may be a good idea to spend some time reading webpack’s documentation on code-splitting

Lazy-Loading with React.lazy and Suspense

Starting with version 16.6, React includes a built-in React.lazy function that makes it very easy to split an application into lazy-loaded components using dynamic imports.

You can turn this:

import StockChartContainer from "./StockChartContainer";
Enter fullscreen mode Exit fullscreen mode

Into this:

const StockChartContainer = lazy(() => import("./StockChartContainer"));
Enter fullscreen mode Exit fullscreen mode

And React will automatically load the bundle containing our StockChartContainer component when we try to render it for the first time.

We’ll want to wrap this lazy component inside a Suspense component, which will allow us to show some fallback content while things are being loaded. Let’s see what that looks like.

Example

In this example we are going to be loading a complex component containing KendoReact’s StockChart, but only after the user clicks on a button. This way we’ll avoid sending the user more code than they need on initial load.

We’ll store state to track whether our complex component needs to be displayed:

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      showChart: false
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, we’ll implement a handleClick function that will toggle state when the user clicks a button:

class App extends Component {
  // ...

  handleClick = () => {
    this.setState(prevState => ({
      showChart: !prevState.showChart
    }));
  };
}
Enter fullscreen mode Exit fullscreen mode

Now we just need to put it all together in the render method:

const StockChartContainer = lazy(() => import("./StockChartContainer"));

class App extends Component {
  // ...

  render() {
    const { showChart } = this.state;
    const buttonText = showChart ? "Hide Stock Chart" : "Show Stock Chart";
    const chartComponent = showChart ? <StockChartContainer /> : null;
    const loadingComponent = <div>Loading...</div>;

    return (
      <div className="App">
        <header className="App-header">
          <h1 className="App-title">Stock Chart</h1>
          <div className="App-button">
            <Button primary={true} onClick={this.handleClick}>
              {buttonText}
            </Button>
          </div>
        </header>
        <div className="App-chart">
          <Suspense fallback={loadingComponent}>{chartComponent}</Suspense>
        </div>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

If we send too much JavaScript to our users, we’ll make the browser’s main thread busy, and it won’t be able to respond to user interaction. Lazy-loading components of our app that are not needed on initial page load will help reduce the amount of work the browser has to do, which will drive down our time-to-interactive, and provide a better experience to our users, especially those on mobile devices. React.lazy and Suspense make it so easy to do that we really have no excuse!😎

Top comments (3)

Collapse
 
dcwither profile image
Devin Witherspoon

Hey, thanks for sharing! BTW, you can tag code blocks with a language to get syntax highlighting by adding the language extension (e.g. js, c, cpp, java) after the the first three backticks.
sample react component wrapped in backticks with javascript syntax highlighting

Collapse
 
shittu_olumide_ profile image
Shittu Olumide

Thanks, well noted!

Collapse
 
_danieldev profile image
Daniel Michael 👨‍💻

We shouldn’t be seeing class components in react guides in 2020, besides that thank you.