In the world of web development, page load times are crucial. Studies show that 53% of mobile site visitors leave a page that takes longer than 3 seconds to load. With the average attention span getting shorter, you only have a few seconds to convince visitors to stay on your site.

This is where code splitting comes in. React code splitting allows you to split your app code into separate bundles that can be loaded on demand. This means you can reduce initial bundle sizes and only load code as needed, dramatically improving load times.

In this post, we’ll cover the benefits of React code splitting, how to implement it in React using React.lazy() and Suspense, and see examples of how it can optimize your app. Read on to unleash the power of code splitting!

The Benefits of React Code Splitting

  • Faster Initial Page Loads- Instead of loading everything up front, you can use React code splitting to only serve the minimum code needed to render the initial route. This significantly reduces the initial bundle size allowing the initial page to load much faster.
  • Lazy Load Code on Demand- React code splitting allows you to lazy load bundles only when needed. For example, loading the code for rarely used routes only when the user navigates to them. This prevents unnecessary code from being loaded upfront.
  • Improved Performance- Fetching bundles on demand means old bundles can be invalidated and refreshed easily without needing to reload the entire page. React code splitting makes it easier to update your code and keep pages performing well.

Implementing Code Splitting with React.lazy()

React has first-class support for code splitting using the React.lazy() API introduced in React 16.6. This allows you to render a dynamic import as a regular component.

Here is an example of how to lazily load the ProfileComponent only when the user navigates to the profile route:

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="profile" element={<ProfileComponent />} />
      </Routes>
    </Suspense>
  );
}

A few key points:

  • React.lazy() lets you render a dynamic import as a regular component
  • The component is loaded lazily when rendered
  • Use Suspense to specify a loading indicator while lazy component loads

This allows the profile code to be fetched in a separate bundle only when needed, improving load time performance.

Code Splitting with React.lazy and Error Boundaries

When using dynamic imports, there is a chance the module fails to load due to network errors. React 16.6 introduced error boundaries to handle these scenarios gracefully:

import React, { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <ErrorBoundary fallback={<div>Error occurred</div>}>
        <OtherComponent />
      </ErrorBoundary>
    </Suspense>
  ); 
}

The component handles errors in the dynamically imported components. This prevents the entire app from crashing if the lazy loaded module fails.

Real-World Examples and Performance Gains

To see the performance benefits of React code splitting, let’s look at some real-world examples.

Example 1: Lazy Loading the Admin Module

Imagine an e-commerce app with separate modules for customers and admins. Admins are only ~10% of users so you can lazy load the admin module.

Without Code Splitting

  • Entire app code including admin code loaded upfront
  • Heavier initial bundle
  • Slower initial page loads

With Code Splitting

const AdminModule = React.lazy(() => import('./AdminModule'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
       <Routes>
         <Route path="admin" element={<AdminModule />} /> 
       </Routes>
    </Suspense>
  )
}
  • Admin module loaded only when accessed
  • Faster initial page loads
  • Overall app performance improves

This optimizes bundles served for the initial route at the cost of some duplication between bundles.

Example 2: React Code Splitting the Checkout Funnel

For an e-commerce app, the checkout funnel is only used by a small % of visitors that make a purchase. It can be intelligently code split:

With Code Splitting

const CheckoutModule = React.lazy(() => import('./CheckoutModule'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
       <Routes>
         <Route path="checkout" element={<CheckoutModule />} />
       </Routes>
    </Suspense>
  )
}
  • Checkout code only loaded when user starts the checkout flow
  • No duplicate code between bundles
  • Overall app performance improves

Across these examples, code splitting optimized bundles to improve initial load times. Apps felt snappier by only loading code as needed.

Summing Up Key Benefits

React Code splitting unlocks many performance benefits:

✅ Lazy load code to reduce initial bundle size
✅ Split code into routes or modules that can be loaded on demand
✅ Only load code needed for the initial route
✅ Use Suspense and Error Boundaries to handle loading/error states
✅ Refresh stale code easily without full page reloads

The result? Faster load times. Happier users.

Ready to Code Split Your React App?

React code splitting can seem complicated at first but it boils down to lazily loading components using React.lazy() and handling suspensions.

As we saw in the examples, even simple React code splitting can unlock big performance improvements.

If you are looking for help setting up code splitting or optimizing your React app performance, get in touch!

I have helped implement performance best practices like code splitting for many React apps. I can analyze your app, identify optimization opportunities, and execute them to boost end-user experience.

Contact me today for consultation on improving your React app speeds with code splitting and other proven performance techniques. Let’s talk!