Code Splitting in ReactJS

React Code Splitting

Bundling is a process performed in the React app using tools like Webpack or Browserify, to take multiple files and merge them into a single file. This single file obtained is called a bundle and is responsible for loading an entire app at once on the webpage.

Example:
App.js:
import { sub } from './math.js';
console.log(sub(50, 25));
math.js:
export function sub(x, y) {
return x - y;
}
Bundle file:
function sub(x, y) {
return x - y;
}
console.log(sub(50, 25));

Code Splitting

To avoid the large bundling, it is preferred to split the bundle. React 16.6.0, introduced a way of performing code splitting. With Code-Splitting user can create multiple bundles that can be dynamically loaded at runtime. It uses React.lazy and Suspense tool/library. These are mainly used to load a dependency lazily and only load it when needed by the user.

Importance of Code Splitting

  • Improves the performance of the app.
  • Improves the impact on memory.
  • Improves the downloaded Kilobytes (or Megabytes) size.

React.lazy:
The React.lazy function allows the rendering of a dynamic import as a regular component, which is again the best way for code splitting.

Before:

import YComponent from './YComponent';
function XComponent() {
return (
<div>
<YComponent />
</div>
);
}

After:

const YComponent = React.lazy(() => import('./YComponent'));
function XComponent() {
return (
<div>
<YComponent />
</div>
);
}

Explanation:
Here the bundle automatically loads. It contains the Ycomp when the Ycomp gets rendered.

Suspense:
There is a need to show some fallback content, in case the module which contains the YComponent is not yet loaded by the function component(XComponent), while we are waiting for it to load, and this is where the suspense component is utilized. Thus the Suspense component is responsible for handling the output when the lazy component is fetched and rendered.

Example:

const YComponent = React.lazy(() => import('./ YComponent'));
function XComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<YComponent />
</Suspense>
</div>
);
}

Example: To combine multiple lazy components with a single Suspense component.

const YComponent = React.lazy(() => import('./ YComponent'));
const ZComponent = React.lazy(() => import('./ ZComponent'));
function XComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<YComponent />
<ZComponent />
</section>
</Suspense>
</div>
);
}

Error boundaries:
An error is produced, if any module fails to load. To handle these errors Error Boundaries are utilized.

Example:

import MyErrorBound from './MyErrorBound';
const YComponent = React.lazy(() => import('./ YComponent'));
const ZComponent = React.lazy(() => import('./ ZComponent'));
const XComponent = () => (
<div>
<MyErrorBound>
<Suspense fallback={<div>Loading...</div>}>
<section>
<YComponent />
<ZComponent />
</section>
</Suspense>
</MyErrorBound>
</div>
);

Route-based Code Splitting

It is very tricky to decide where we introduce code splitting in the app. For this, we have to make sure that we choose the place that will split the bundles evenly without disrupting the user experience. The route is considered to be the best place to start the code splitting in the app. It is especially essential during the page transitions on the web, which takes some amount of time to load.

Example:

import { Switch, BrowserRouter as Router, Route} from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
const Home = lazy(() => import('./routes/Home'));
const Blog = lazy(() => import('./routes/Blog'));
const Services = lazy(() => import('./routes/Contact'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/blog" component={Blog}/>
<Route path="/services" component={Services}/>
</Switch>
</Suspense>
</Router>
);

Named Export:
To import a module using named exports, an intermediate module needs to be created which re-exports it as the default.

YComponent.js:

export const AComponent = /* ... */;
export const BComponent = /* ... */;

AComponent.js:

export {AComponent as default } from "./YComponent.js";

MyApp.js:

import React, { lazy } from 'react';
const AComponent = lazy(() => import("./AComponent.js"));