Tutorial

Code Splitting in React Using React Loadable

Published on April 18, 2018
author

Alligator.io

Code Splitting in React Using React Loadable

Code splitting is a technique used more in more with modern web app development that allows to load chunks of code only when needed. For example, with route-based code splitting, a user can be navigating to different routes of an app and behind the scenes the code for each route only loads upon accessing for the first time. With code splitting, only the minimal amount of code can be loaded when the app initializes and additional code is loaded on demand. This can help tremendously with performance by allowing for a reduced initial bundle size.

React Loadable is a library by @jamiebuilds that makes it easy to implement code splitting in React and that embraces React’s component model. It accomplish its magic using dynamic imports and webpack automatically splits dynamic imports into separate chunks when bundling.

Let’s quickly go over how to use React Loadable.

Installation

Just add the react-loadable package to your project using npm or Yarn:

$ npm install react-loadable

# or
$ yarn add react-loadable

Usage

Let’s create a contrived example to illustrate how simple Loadable is. First, SomeComponent:

components/SomeComponent.js
import React from 'react';

function SomeComponent() {
  return <h1>Some Component! 💣🚀👨‍🎤🤘</h1>;
}

export default SomeComponent;

And then let’s use it in our App component:

App.js
import React, { Component, Fragment } from 'react';
import SomeComponent from './components/SomeComponent';

class App extends Component {
  state = {
    showComponent: false
  };

  handleClick = () => {
    this.setState({
      showComponent: true
    });
  };

  render() {
    if (this.state.showComponent) {
      return <SomeComponent />;
    } else {
      return (
        <Fragment>
          <h1>Hello!</h1>
          <button onClick={this.handleClick}>Click me!</button>
        </Fragment>
      );
    }
  }
}

export default App;

Notice how the component is only rendered into the view once the user clicks on the button. Obviously with such a simple component it doesn’t make a difference, but with larger components in an app that’s non-trivial, code-splitting that component away can be a good idea.

Let’s refactor a bit to code split using React Loadable:

App.js
import React, { Component, Fragment } from 'react';
import Loadable from 'react-loadable';

function Loading() {
  return <h3>Loading...</h3>;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

class App extends Component {
  state = {
    showComponent: false
  };

  handleClick = () => {
    this.setState({
      showComponent: true
    });
  };

  render() {
    if (this.state.showComponent) {
      return <SomeComponent />;
    } else {
      return (
        <Fragment>
          <h1>Hello!</h1>
          <button onClick={this.handleClick}>Click me!</button>
        </Fragment>
      );
    }
  }
}

export default App;

The Loadable higher-order component takes an object with two keys: loader and loading:

  • loader: Expects a function that returns a promise that resolves to a React component. Dynamic imports using import() return a promise, so all we have to do is point to the location of the component to load.
  • loading: Expects a component to render while the code is being loaded.

And it’s as easy as that! If you have a look at the Network tab in your browser’s Devtools, you’ll see the chunk being loaded when the button is clicked.

Loading Delay

If components are loaded quickly, having an intermediary loading component can become a source of visual annoyance in the UI. Luckily, Loadable provides an easy workaround in the form of a pastDelay prop that’s passed to the loading component and that evaluates to true once a certain delay has passed:

// ...

function Loading({ pastDelay }) {
  return pastDelay ? <h3>Loading...</h3> : null;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

// ...

The default delay is 200ms, but you can change that by passing a delay config to the Loadable HOC. Here for example we change the maximum delay to 60ms:

function Loading({ pastDelay }) {
  return pastDelay ? <h3>Loading...</h3> : null;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading,
  delay: 60
});

Errors

Another prop gets passed-in to the loading component, error, which makes it easy to render something else if an error occurs while trying to load the component:

function Loading({ error }) {
  if (error) {
    return 'oh-noes!';
  } else {
    return <h3>Loading...</h3>;
  }
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

Route-Based Code Splitting

Oftentimes the easiest way to code-split an app is at the route level. Since routes in React when using React Router v4 are just components, it’s just as easy to use React Loadable to load the code for the different routes on-demand.

Here we’ll go over a simple example of route-based code splitting using React Loadable. First, make sure that we also have react-router-dom available in our project:

$ npm install react-router-dom

# or
$ yarn add react-router-dom

In the following example, we import the Dashboard component statically as it’ll be needed immediately on the root route and we use Loadable to only load the Settings and AddUser components when their respective route is activated:

import React, { Component } from 'react';
import Loadable from 'react-loadable';
import { Link, Route, BrowserRouter as Router } from 'react-router-dom';

import Dashboard from './components/Dashboard';

function Loading({ error }) {
  if (error) {
    return 'Oh nooess!';
  } else {
    return <h3>Loading...</h3>;
  }
}

const Settings = Loadable({
  loader: () => import('./components/Settings'),
  loading: Loading
});

const AddUser = Loadable({
  loader: () => import('./components/AddUser'),
  loading: Loading
});

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <Link to="/">Dashboard</Link>
          <Link to="/settings">Settings</Link>
          <Link to="/add-user">Add User</Link>

          <Route exact path="/" component={Dashboard} />
          <Route path="/settings" component={Settings} />
          <Route path="/add-user" component={AddUser} />
        </div>
      </Router>
    );
  }
}

export default App;

🏇 And with this, you should be off to the races with code splitting! Have a look at the project’s Readme for a mode in-depth look at the API and for documentation on advanced topics such as server-side rendering.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Alligator.io

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.