21
React Code Splitting
Before Knowing about Code Splitting we need to know Why we need Code Splitting these first we need to know about bundling. Bundling is a process that takes multiple files and merges them into a single file, which is called a bundle. Most React apps will have their files “bundled” using tools like Webpack, Rollup, or Browser. Let's see an example:
App:
import { add } from './math.js';
// math.js
export function add(a, b) {
return a + b;
}
console.log(add(2, 4)); // 6
Bundle:
function add(a, b) {
return a + b;
}
console.log(add(2,4)); // 6
As our app grows, our bundle will grow, especially when using large third-party libraries. If the bundle size gets large, it takes a long time to load on a webpage. Resolving these issues Code splitting comes into the scenario.
Code Splitting
Code-Splitting is a feature supported by Webpack and Browserify, which can create multiple bundles that can be dynamically loaded at runtime. Code splitting your app can help you “lazy-load” just the things that are currently needed by the user.
Features
- The code splitting improves the performance of the app
- The code splitting improves the impact on memory
- The code splitting improves the downloaded Kilobytes (or Megabytes) size
import()
The best way to introduce code-splitting into your app is through the dynamic import(). When Webpack comes across this syntax, it automatically starts code-splitting your app. If you’re using Create React App, this is already configured for you and you can start using it immediately.
Before:
import { sub } from './math';
console.log(sub(20, 10));
After:
import("./math").then(math => {
console.log(math.sub(20, 10));
});
React.lazy:
The React.lazy function lets you render a dynamic import as a regular component.React.lazy takes a function that must call a dynamic import(). This must return a Promise which resolves to a module with a default export containing a React component. React.lazy and Suspense are not yet available for server-side rendering.
Before:
import OtherComponent from './ExampleComponent';
After:
const OtherComponent = React.lazy(() => import('./ExampleComponent'));
This will automatically load the bundle containing the ExampleComponent when this component is first rendered.
React.lazy components are not yet available for server-side rendering. For code-splitting in a server-rendered app, it is recommended to use Loadable Components.
Suspense:
If the module which contains the ExampleComponent is not yet loaded by the function component(MyComponent), then the lazy component should then be rendered inside a Suspense component, which allows us to show some fallback content while we’re waiting for the lazy component to load.
*The fallback prop accepts any React elements that you want to render while waiting for the component to load.
*You can place the Suspense component anywhere above the lazy component.
*You can even wrap multiple lazy components with a single Suspense component.
Before:
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
After:
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}
Suspense components are not yet available for server-side rendering. For code-splitting in a server-rendered app, it is recommended to use Loadable Components.
Error boundaries:
If any module fails to load, for example, due to network failure, we will get an error that can handle these errors with Error Boundaries. Once we have created the Error Boundary, we can use it anywhere above our lazy components to display an error state.
import MyErrorBoundary from './MyErrorBoundary';
const ExampleComponent = React.lazy(() => import('./ ExampleComponent'));
const ExamComponent = React.lazy(() => import('./ ExamComponent'));
const MyComponent = () => (
<div>
<MyErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<section>
<ExampleComponent />
<ExamComponent />
</section>
</Suspense>
</MyErrorBoundary>
</div>
);
Route-based code splitting:
Deciding where in your app to introduce code splitting can be a bit tricky. You want to make sure you choose places that will split bundles evenly but won’t disrupt the user experience.
A good place to start is with routes. Most people on the web are used to page transitions taking some amount of time to load. You also tend to be re-rendering the entire page at once so your users are unlikely to be interacting with other elements on the page at the same time.
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Suspense>
</Router>
);
Named Exports:
React.lazy currently supports only default exports. An intermediate module that re-exports as default has to be created if one wants to import a module that uses named exports. This ensures the working of tree shaking and prevents the pulling in of unused components.
Components.js
export const Component = /* ... */;
export const MyUnusedComponent = /* ... */;
Component.js
export { Component as default } from "./Components.js";
MyApp.js
import {React, lazy} from 'react';
const Component = lazy(() => import("./Component.js"));
Hopefully, Code Splitting is a bit clear by now. It helps to improve your efficiency in writing React. If any queries regarding this write them down in the comment below. Thank you for your time and I hoped my blog is helpful for you.
21