How to Use NextJS Loader for Page Transitions
Tags: nextjs, loader, webdev, javascript
Published: 2022-03-09 09:29:01

**Context**
NextJs does Automating Code-Splitting on the basis of [pages](https://nextjs.org/docs/basic-features/pages), so each time there is a route change, nextjs dynamically loads the necessary modules.

If you're using Nextjs [Link](https://nextjs.org/docs/api-reference/next/link) Component, it prefetches the necessary modules related to page Link has href of, whenever it comes in viewport and whenever user hovers over it by default to make user experience smooth.

But in some scenarios adding a loader for page transitions when modules are heavy or they are fetched yet boosts the user experience a lot.

---


**Code**

* Let's create a Loader Svg First, I'm using a svg loader from [here](https://codepen.io/nikhil8krishnan/pen/rVoXJa).

```
export const SvgLoader = () => (
  <div style={{width: '100px'}}>
    <svg
      version="1.1"
      id="L4"
      xmlns="http://www.w3.org/2000/svg"
      x="0px"
      y="0px"
      viewBox="0 0 100 100"
      enable-background="new 0 0 0 0"
    >
      <circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
        <animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.1" />
      </circle>
      <circle fill="#fff" stroke="none" cx="26" cy="50" r="6">
        <animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.2" />
      </circle>
      <circle fill="#fff" stroke="none" cx="46" cy="50" r="6">
        <animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.3" />
      </circle>
    </svg>
  </div>
);
```
* Now Create  Loader Component that has the logic for when to show the loader.

```
import React, { useState } from "react";
import { SvgLoader } from "./SvgLoader";

export const Loader = () => {
  const router = useRouter();
  const [isLoaderVisible, setIsLoaderVisible] = useState(false);

  React.useEffect(() => {
    const handleRouteChange = (url, { shallow }) => {
      setIsLoaderVisible(true);
    };

    const handleRouteComplete = (url, { shallow }) => {
      setIsLoaderVisible(false);
    };

// here we subscribe to router change start and complete events
    router.events.on("routeChangeStart", handleRouteChange);
    router.events.on("routeChangeComplete", handleRouteComplete);

// unsubscribing to router events when component unmounts to prevent memeory leaks
    return () => {
      router.events.off("routeChangeStart", handleRouteChange);
      router.events.off("routeChangeComplete", handleRouteComplete);
    };
  }, []);

  if (isLoaderVisible) {
    return (
      <div
        style={{
          position: "fixed",
          inset: 0,
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        <SvgLoader />
      </div>
    );
  } else return null;
};
```

* Now we can use the above loader in any of the Higher Order compoents or even in _app.js

```
import {Loader} from '../components/Loader'

function MyApp({Component, pageProps}: any) {
  return (
    <>
      <Loader />
      <Component {...pageProps} />
    </>
  );
}
```

Output
Whenever there will be a page change, below loader will show up, incase modules are not imported.
Gist: https://gist.github.com/arshkkk/b3555c65441ff170d942c4e5309360a2

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fafe1ojhyzexrjyjb85j.png)