Tutorial

Code Splitting in React Using React Loadable

Published on April 18, 2018
Default avatar

By Alligator.io

Code Splitting in React Using React Loadable

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.

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 us


About the authors
Default avatar
Alligator.io

author

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!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

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

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow ā€” whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel