Home Services Portfolio Blog
 
Home Services Portfolio Blog

Performance Optimization for React App’s using code splitting and lazy loading

Behind good security, performance is one of the most important things to consider when creating any kind of web or mobile app. Amazon found out over 10 years ago that for every 100ms of latency it cost them 1% in sales, click on this article if you want to learn more.

With that being said it’s not necessary to go overboard on performance optimization’s at the beginning of your project if your app is already running efficiently to begin with. Its best to use some fundamental principal’s of performance and only go above and beyond that when necessary.

React lazy and Suspense are two tools you can use to help with those optimizations. How react lazy works is by asynchronously importing components into your app. This is helpful because by default webpack bundles all of your .js files into one chunk.js file and downloads the whole application when a user first visits the app.

If you have many components in your app or are using react-router and have alot of routes inside the app, then it might not be necessary to download all the .js files at one time. Being able to split your code into smaller chunk.js files instead of one big file can help your app’s initial render time be much faster if it only downloads what it needs when its needs it. That’s where lazy loading and Suspense can help because lazy loaded components wont be downloaded until you navigate to that component.

To implement lazy loading and Suspense is pretty straight forward, first you import lazy and Suspense from react.

import React, { lazy, Suspense } from "react";

Then any components that will not be rendered initially can be imported with lazy loading like so

const HomePage = lazy(() => import("./pages/homepage/homepage.component"));
const ShopPage = lazy(() => import("./pages/shop/shop.component"));
const Contact = lazy(() => import("./components/contact/contact.component"));
const SignIn = lazy(() =>
  import("./pages/sign-in-and-sign-up/sign-in-and-sign-up.component")
);

The components are imported using a callback function which returns a promise and this is where Suspense comes in to wrap the lazy loaded components and render a fallback component until the promise is resolved

          <Suspense fallback={<Spinner />}>
            <Route exact path="/" component={HomePage} />
            <Route path="/shop" component={ShopPage} />
            <Route exact path="/contact" component={Contact} />
            <Route exact path="/signin" component={SignIn} />
          </Suspense>

The fallback prop on the Suspense component is used to output a spinner component or anything you would like to render while the promise from the lazy loaded callback function is resolved so the user see’s some content in the meantime. Another important component to use here would be an ErrorBoundary component. The reason to use an ErrorBoundary is because now your components are being loaded asynchronously from the server. So if a user of your app navigate’s to one of those components while there is a server error of some kind, you want to output some custom error to display to the user. To implement an ErrorBoundary component it’s not that difficult. First you create a new component for your error handling and there are two important lifecycle methods which allow you to do just that, getDerivedStateFromProps and componentDidCatch.

import React from "react";

class ErrorBoundary extends React.Component {
  constructor() {
    super();

    this.state = {
      error: false
    };
  }

  static getDerivedStateFromError(error) {
    // process the error
    return { error: true };
  }

  componentDidCatch(error, info) {
    // get the info from the error
    console.log(error);
  }

  render() {
    return (
     <div>
      {
     this.state.error 
     ? <div> Something went wrong </div> 
     : this.props.children
      }
     </div>
   );
  }
}

export default ErrorBoundary;

As you can see the ErrorBoundary component depends on the getDerivedStateFromProps and componentDidCatch. The most important method is the getDerivedStateFromProps method because that’s what makes your app aware of any child component’s throwing an error inside the ErrorBoundary component. The other componentDidCatch lifecycle method is more for giving you info about the error itself.

These are just some of the methods to use for performance optimization in your react app if it is big enough or has enough traffic to need these optimizations.