DEV Community

Cover image for How to Use NextJS Loader for Page Transitions
arshkkk
arshkkk

Posted on

How to Use NextJS Loader for Page Transitions

Context
NextJs does Automating Code-Splitting on the basis of pages, so each time there is a route change, nextjs dynamically loads the necessary modules.

If you're using Nextjs 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.
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>
);
Enter fullscreen mode Exit fullscreen mode
  • 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;
};
Enter fullscreen mode Exit fullscreen mode
  • 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} />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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

Discussion (0)