As React applications grow in complexity, managing performance becomes essential. Large bundles can slow down initial load times, making the user experience less responsive. To address this, lazy loading and code splitting are two key techniques that allow React applications to load faster by breaking down large bundles into smaller, more manageable chunks.
Lazy loading is a design pattern that delays the loading of resources (such as components, images, or scripts) until they are needed. Instead of loading everything at once when a page is requested, resources are only loaded when the user interacts with the relevant part of the application.
Code splitting is the process of dividing the JavaScript bundle into smaller chunks. When code splitting is combined with lazy loading, these chunks are only loaded when they are required, improving both the performance and the user experience of a React application. Code splitting allows you to load parts of your application on demand rather than loading the entire app upfront.
React provides built-in support for lazy loading using the React.lazy()
function. Let’s explore how to use it with practical examples.
The React.lazy()
function allows us to load a component dynamically when it is needed. Let’s see how this works with an example.
import React, { Suspense } from 'react';
// Lazy load the component
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
Welcome to My App
Loading... }>
React.lazy()
function is used to import LazyComponent
only when it is needed.Suspense
component acts as a fallback UI that shows a loading state while the lazy-loaded component is being fetched.LazyComponent
is being fetched. Once it is loaded, the content of LazyComponent
will be rendered.You can also lazy load multiple components in the same way:
import React, { Suspense } from 'react';
const LazyComponentOne = React.lazy(() => import('./ComponentOne'));
const LazyComponentTwo = React.lazy(() => import('./ComponentTwo'));
function App() {
return (
Welcome
Loading components... }>
Loading components...
will be displayed until they are ready.React uses a popular tool called Webpack to bundle JavaScript files. Code splitting can be achieved using both Webpack and React’s features. The primary method to achieve code splitting in React is by using dynamic import()
statements along with React.lazy()
.
When we use React.lazy()
with dynamic imports, Webpack automatically creates separate bundles for the lazy-loaded components. Let’s see how this works in more detail.
import React, { Suspense } from 'react';
const LazyHeader = React.lazy(() => import('./Header'));
const LazyFooter = React.lazy(() => import('./Footer'));
function App() {
return (
Loading header... }>
Main content of the app goes here...
Loading footer...
Header
and Footer
components into separate bundles. They will be loaded only when the user interacts with the corresponding part of the application.Suspense
indicates which component is being loaded at any given moment.In some cases, you may want to use dynamic imports without relying on React.lazy()
. For example, when dealing with non-React components or other resources like scripts, you can still leverage dynamic imports:
function loadScript() {
import('./someLibrary')
.then((module) => {
const library = module.default;
library.doSomething();
})
.catch((error) => {
console.error("Failed to load library", error);
});
}
function App() {
return ;
}
export default App;
doSomething()
function.In a single-page React application (SPA), routing is a common use case for lazy loading. You can lazy load entire pages or views, making the initial load faster while keeping the bundle size smaller.
You can lazy load route components using React.lazy()
with React Router.
import React, { Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = React.lazy(() => import('./Home'));
const About = React.lazy(() => import('./About'));
function App() {
return (
Loading...
Home
and About
components are lazy-loaded when the user navigates to their respective routes.Suspense
component ensures that the fallback UI is displayed while the components are being loaded./about
page, the “About” component will load lazily, improving the performance by splitting routes into smaller bundles.Preloading can be useful when you anticipate that the user will navigate to a specific part of the application. You can preload components so they are ready in the background.
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
// Preload the component
LazyComponent.preload();
function App() {
return (
Welcome
Loading... }>
LazyComponent.preload()
function will preload the component when the app loads, but it will only render when needed. This can help reduce perceived loading times.When lazy loading components, network errors or other issues can prevent the component from loading correctly. React’s Error Boundaries can be used to catch these errors and display a fallback UI.
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return Something went wrong.
;
}
return this.props.children;
}
}
function App() {
return (
Welcome
Loading... }>
ErrorBoundary
component catches errors during rendering, providing a fallback UI if something goes wrong with the lazy-loaded component.We explored lazy loading and code splitting in React from the basics to more advanced concepts. By using React.lazy(), Suspense, and dynamic imports, you can improve the performance of your React applications significantly by reducing initial load times and keeping the bundle size manageable. Happy Coding!❤️