React router Lazy load route components
Tags: react, webdev, tutorial, beginners
Published: 2022-09-18 13:11:28

Performance optimization is the key to having an efficiently functional application and is done by monitoring and analyzing various metrics of an application and identifying ways to improve it. One of the most fundamental and important ways is to lazily load the routes/pages based on user requirements and not fetch the whole chunk at the beginning which can lead to a high load time of the page that results in an increase in user dropoff number.

For best practice, web developers code split large bundles into smaller ones because it enables them to lazy load files on demand and improves the performance of the React application. In this post, we’ll look at how to split our code based on routes using [React Router](https://reactrouter.com/en/main). The idea is simple, don’t download code until the user needs it. The below example is just a simple boilerplate example. In practice, it can be a little more complicated.

Enough of Theory let's dive in...

### Install the dependency:
`yarn add react-router-dom@6`


### Wrapping App component:
Import [BrowserRouter](https://reactrouter.com/en/main/router-components/browser-router) from react-router-dom near the top of your file and wrap your <App /> in a <BrowserRouter> so that all the necessary routing methods are available across your application.

File: `main.tsx`

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);
```

### Creating routes config:
This config will hold all the necessary mapping for our routes like route name, element/component to load lazily, and path. Here we are using [useRoutes](https://reactrouter.com/en/main/hooks/use-routes) hook, it is basically the functional equivalent for `<Routes>`.

File: `routes/index.ts`

```javascript
import { useRoutes } from 'react-router-dom';
import { lazyLoadRoutes } from './LazyLoadRoutes';

export function RouterElement() {
  const routes = [
    {
      path: '/',
      name: 'Home',
      element: lazyLoadRoutes('Home'),
    },
    {
      path: 'about',
      name: 'About',
      element: lazyLoadRoutes('About'),
    },
    {
      path: 'services',
      name: 'Services',
      element: lazyLoadRoutes('Services'),
    },
  ];

  return useRoutes(routes);
}
```

### Lazy load component:
As the name says the main purpose of this component is to lazily load the mentioned component. First we lazy load the mentioned component using [React.lazy](https://reactjs.org/docs/react-api.html#reactlazy), we wrap around [React.Suspense](https://reactjs.org/docs/react-api.html#reactsuspense) with the fallback text(this can be a loader component as well). Please note that we can tweak the function component so that it takes the path and not just the component name.

File: `routes/LazyLoadRoutes.tsx`

```javascript
import { lazy, Suspense } from 'react';

/**
 * Lazily load the mentioned component which resides in the page directory
 * This method will be used in routes so that the files are loaded only
 * When users are on that route
 */
export function lazyLoadRoutes(componentName: string) {
  const LazyElement = lazy(() => import(`../pages/${componentName}.tsx`));

  // Wrapping around the suspense component is mandatory
  return (
    <Suspense fallback="Loading...">
      <LazyElement />
    </Suspense>
  );
}
```

### Navigation bar for route redirection:
Creating navigation route for our pages which are Home, About and Services.

File: `App.tsx`

```javascript
import { Link } from 'react-router-dom';
import { RouterElement } from './routes';
import './App.css';

function App() {
  return (
    <div className="App">
      <nav>
        <Link to="/">Home</Link>
        <Link to="about">About</Link>
        <Link to="services">Services</Link>
      </nav>
      <RouterElement />
    </div>
  );
}

export default App;
```

### Working Example Link:
As you can see below the chunk for About and Services loads only when we visit that route and the chunk gets cached in the browser so that it is not fetched again in the same session.


![dynamix route example gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzmhjkiaavnqq2t8qcbz.gif)


{% embed https://stackblitz.com/edit/vitejs-vite-wrxjje?file=src%2Froutes%2FLazyLoadRoutes.tsx %}

Do let me know if there are any other nifty ways in the comments below.
Thanks for your time reading. Drop a few ❤️ or 🦄 if you liked it.