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>
);
- 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
Top comments (0)