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.
Just add the react-loadable package to your project using npm or Yarn:
$ npm install react-loadable
# or
$ yarn add react-loadable
Let’s create a contrived example to illustrate how simple Loadable is. First, SomeComponent:
import React from 'react';
function SomeComponent() {
return <h1>Some Component! 💣🚀👨🎤🤘</h1>;
}
export default SomeComponent;
And then let’s use it in our App component:
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:
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
:
import()
return a promise, so all we have to do is point to the location of the component to load.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.
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
});
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
});
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.
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.
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!