When you deploy a React application using a tool like Webpack, you are employing a technique called bundling.
Build tools like Webpack are, after all, module bundlers.
So when you arrive at a page served by a web application, the page requests a bundle; that is, a file or files that contain all of the code necessary for that page to function.
Often when we build a page, however, we include quite a bit of code that isn't immediately necessary.
To keep our application lean and fast, we should strive to serve only what is absolutely necessary for the UI on first paint.
One way to achieve this is by code splitting.
Code splitting allows us to defer to the loading of various resources until later, when they are actually needed.
For example, let's say a user hits a route and arrives at a page in your web application.
Maybe this page has a number of heavy modals.
Maybe this page has a number of routes that load additional content elsewhere.
Maybe it contains a heavy library that is needed later, but is being loaded first on the home page.
If our goal is to render the page contents as fast as possible, we need to abstract away everything that isn't immediately required and acting to slow your load time down.
Let's explore a few ways to code-split your web app using React's lazy method and Suspense component.
First, let's bootstrap a project with
In your command line:
> npx create-react-app codesplitting-in-react
Then launch the dev server at
port:3000 by following up the installation with:
> cd codesplitting-in-react > yarn start
Excellent, we have the basic spinning React logo that we've come accustomed to.
Open the project in your favourite editor and let's get started.
In React, we have the ability to import a function called
lazy, and a component called
lazy does is allow us to differ the loading of a component or resource until it is needed.
When compined with
Suspense, the lazy component will only be rendered once loaded, and we are able to provide a fallback while it loads (such as
Let's work through an example.
Reach Router and Route Setup
Shut down the server with
control + c and install Reach Router:
Reach Router is a simple, lightweight router developed by the people behind React Router.
In your terminal:
> yarn add @reach/router > yarn start
What we are going to do now is:
So, go ahead and create a new file called
Main.js and pull out the code from within the
App.js will now look a whole lot skinnier.
Make sure you import
Main.js and place it where you removed it, as seen below.
As always, avoid those class methods.
So visually, nothing will have changed.
While we pulled the code into a new component, the code didn't change, and so everything will still look the same.
Now let's import
ReachRouter and use our
Main component as our default route.
ReachRouter is very straight forward to use:
pathprop for each route, with
Mainbeing the default.
App.js now as follows
Again, nothing will have changed visually, but now we have
Main set as our default route.
Now let's create a second child route, assign it a path, and have the React logo link to this path.
Create a new file called
SplitThis.js, and set it up to simply render it's name as an
Next, import this component into
App.js and add it as a child route under
<Main> with the path
@reach/router to wrap the React logo in, and direct it to
Now we can see that our routes are set up, and that clicking the logo takes us to our other page.
First, to get an understanding about how bundling works, let's open up our inspector in our browser.
In the inspector, select
Network -> JS, and refresh the page.
When you refresh, you will see the different bundles coming through the network.
You can also see their sizes. Right now, all of our bundles are very, very small.
Typically we wouldn't even consider codesplitting unless a bundle was greater than 30kb.
But for the sake of example, let's import
Suspense and split out our
App.js to include the above imports, wrap the routes in
Suspense with a fallback tag, and import
SplitThis lazy loaded within
Suspense, that component will not be included in the main bundle.
Instead it will be retrieved from the server only when the user requests it by clicking on the React logo.
Watch what happens now when we load the app and then navigate to our
We can see that the
SplitThis route was loaded as a seperate bundle.
Another very important thing to note is that once that bundle is loaded and you navigate elsewhere, it won't be reloaded when you return.
The bundler is smart enough to see that the bundle it requires was already loaded previously and so does not attempt to retrieve it again.
Some libraries are very heavy.
Typically, if you do not plan to use absolutely all of a library, you should only be importing the pieces that you need.
In the same way as we did with code splitting a route, let's do the same with a library within a component.
First, let's install a heavy library to import, such as
Shut down your server and install the
> yarn add moment > yarn start
Now simply import
Additionally, let's allo import
lodash, which comes included with
Now take a look at the load on the Network.
Upon clicking our child route, we see network results like this:
The first 3 lines are our initial load into main, and then when we click our child route we recieve 2 more bundles, one of them being fairly large since it is importing 2 large libraries.
By using React’s lazy method and Suspense component we gain the ability to control how the application bundler decides what goes where.
The result: lean pages that load quickly (if used correctly).
No one wants to work super hard to create an awesome app, only to have users dropping off because of a slow first paint.
So, be lazy.