React is a library for creating front-end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.
In this article, we’ll look at how to make apps load faster by splitting code so that only the parts that are needed will load.
Code-Splitting
We need code-splitting so that product React bundles won’t be too big. As our apps get bigger, the production bundles will also get bigger and take longer to load if we don’t split them and load them only when needed.
Create React App has code-splitting support built-in. We can use the lazy
and import
functions from React to achieve this.
For example, we can use those functions as follows:
Foo.js
:
import React from "react";export default function Foo() {
return <div>foo</div>;
}
App.js
:
In the code above, we have Foo.js
with the Foo
component.
Then, in App.js
, we have the App
component that has Suspense
to load the fallback. UI has the Foo
import loads. We need this since Foo
is loaded at runtime.
React.lazy
loads the Foo
component at runtime instead of at build time. It also splits the code from the bundle into a separate file so that each bundled file is smaller.
We’ll get an error telling us to add a fallback UI with the Suspense
component if it’s missing.
The fallback
prop accepts any React element that we want to render while waiting for the component to load. We can place Suspense
anywhere above the lazy component.
Wrapping multiple elements in a single Suspense
element also works.
Error Boundaries
To fail gracefully when other modules fail to load, such as where network failure occurs, we can use error boundary components.
To use them, we wrap them around the Suspense
component as follows:
ErrorBoundary.js
:
Foo.js
:
import React from "react";
export default function Foo() {
return <div>foo</div>;
}
App.js
:
In the code above, we added the ErrorBoundary
component in ErrorBoundary.js
.
Then, in App
, we wrapped it around our Suspense
component, which lets us catch any errors that occur when loading the Foo
component.
Route-Based Code-Splitting
Many React apps are single-page apps. They’ll have routes to map URLs to components.
We can split code based on routes. For example, we can incorporate React Router routes into our app and split code based on routes as follows:
Foo.js
:
import React from "react";
export default function Foo() {
return <div>foo</div>;
}
Bar.js
:
import React from "react";
export default function Bar() {
return <div>bar</div>;
}
App.js
:
In the example above, we add the Router
component around all our components.
We put the Route
s inside the Suspense
component so that they can be lazy-loaded. That is, they load only when we load the route in our browser.
This is also why we need the Suspense
component around the routes. We need the fallback UI so that it’ll be shown when the routes are loading.
Named Exports
React.lazy
only supports default exports. If our module uses named exports, then we have to create an intermediate module that re-exports it as default.
For example, we can arrange our code as follows:
Foo.js
:
import React from "react";
export const Foo = function() {
return <div>foo</div>;
};
FooDefault.js
:
import { Foo } from "./Foo";
export default Foo;
App.js
:
import React, { Suspense } from "react";
const FooComponent = React.lazy(() => import("./Foo"));
export default function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<FooComponent />
</Suspense>
);
}
In the code above, we have FooDefault.js
that exports Foo
as a default export.
Then, we imported it in App.js
with React.lazy
.
Conclusion
Code-splitting is easy with Create React App and React. React has the lazy
method to import components on the fly.
We need a fallback UI so that we can see something when the dynamically imported component loads.
Error boundaries are also supported and we can use it to gracefully fail when a dynamically imported component fails to load.
Code-splitting is also supported by React Router. React.lazy
is smart enough to split code by route.