How to show loader and progress bar when changing page routes in next js (react js)
Today we would like to talk about the most common question: how to add a loader when changing page route in nextjs. For this work to done we’ll use next router event. We actuality use routeChangeStart() & routeChangeComplete() event.
routeChangeStart(url): Fires when a route starts to change. When you click on a route then immediately call this router event.
routeChangeComplete(url): Fires when a route changed completely.
Note: Here url is the URL shown in the browser, including the basePath.
We use a Custom App (pages/_app.js) for this example to subscribe to the event because it's not unmounted on page navigations, but you can subscribe to router events on any component in your application.
Router events should be registered when a component mounts (useEffect or componentDidMount / componentWillUnmount) or imperatively when an event happens.
Let's start...
First we set a state for loading state. Initially it’ll be false.
const [loading, SetLoading] = useState(false);
Then change loading state value we start to change route and call routeChangeStart.
Router.events.on('routeChangeStart', (url) => { SetLoading(true); });
Now we have to create a simple Loader component named Loader.js
export default MyApp; import React from 'react'; import Image from 'next/image' const Loader = () => { return ( <div> <div className='loaderContainer'> <Image src=’loaderImagePath’ alt="loading… " /> </div> </div> ); }; export default Loader;
now, we give a condition above on component line in pages/_app.js
return ( <> {loading && <Loader />} <Component {...pageProps} /> </> );
Final step is after completing router state change we have to stop loader and then we use routeChangeComplete router event. In this function event we just loading state set true to false. That’s it.
Router.events.on('routeChangeComplete', (url) => { SetLoading(false); });
Final pages/_app.js file is –
import { useEffect, useState } from 'react'; import Router from "next/router" import Loader from '../components/Loader' function MyApp({ Component}) { const [loading, SetLoading] = useState(false); useEffect(() => { Router.events.on('routeChangeStart', (url) => { SetLoading(true); }); Router.events.on('routeChangeComplete', (url) => { SetLoading(false); }); }, []); return ( <> {loading && <Loader />} <Component {...pageProps} /> </> ); } export default MyApp;