I am trying to implement a loading screen when changing routes in my Nextjs app ,for example /home -> /about.
My current implementation is as follows. I am setting the
New Update with NProgress:
import Router from 'next/router'
import Link from 'next/link'
import Head from 'next/head'
import NProgress from 'nprogress'
Router.events.on('routeChangeStart', (url) => {
console.log(`Loading: ${url}`)
NProgress.start()
})
Router.events.on('routeChangeComplete', () => NProgress.done())
Router.events.on('routeChangeError', () => NProgress.done())
export default function App({ Component, pageProps }) {
return (
<>
<Head>
{/* Import CSS for nprogress */}
<link rel="stylesheet" type="text/css" href="/nprogress.css" />
</Head>
<Component {...pageProps} />
</>
)
}
If you use Tailwind CSS, copy the code from here: https://unpkg.com/nprogress@0.2.0/nprogress.css and paste the code into your global CSS file.
if you want to disable the spinner add the below code in your _app.tsx/jsx
file and remove the spinner styles from CSS.
NProgress.configure({ showSpinner: false });
Source Links:
Why not use nprogress
as follows in _app.js
import React from 'react';
import Router from 'next/router';
import App, { Container } from 'next/app';
import NProgress from 'nprogress';
NProgress.configure({ showSpinner: publicRuntimeConfig.NProgressShowSpinner });
Router.onRouteChangeStart = () => {
// console.log('onRouteChangeStart triggered');
NProgress.start();
};
Router.onRouteChangeComplete = () => {
// console.log('onRouteChangeComplete triggered');
NProgress.done();
};
Router.onRouteChangeError = () => {
// console.log('onRouteChangeError triggered');
NProgress.done();
};
export default class MyApp extends App { ... }
Link to nprogress.
You also need to include style file as well. If you put the css file in static
directory, then you can access the style as follows:
<link rel="stylesheet" type="text/css" href="/static/css/nprogress.css" />
Make sure the CSS is available in all pages...
It will work for all your routes changing.
Using the new hook api, this is how I would do it..
function Loading() {
const router = useRouter();
const [loading, setLoading] = useState(false);
useEffect(() => {
const handleStart = (url) => (url !== router.asPath) && setLoading(true);
const handleComplete = (url) => (url === router.asPath) && setLoading(false);
router.events.on('routeChangeStart', handleStart)
router.events.on('routeChangeComplete', handleComplete)
router.events.on('routeChangeError', handleComplete)
return () => {
router.events.off('routeChangeStart', handleStart)
router.events.off('routeChangeComplete', handleComplete)
router.events.off('routeChangeError', handleComplete)
}
})
return loading && (<div>Loading....{/*I have an animation here*/}</div>);
}
Now <Loading/>
is going to show up whenever the route will change...
I animate this using react-spring, but you can use any library you prefer to do this.
You can even take a step further and modify when the component shows up by modifying the handleStart
and handleComplete
methods that gets a url
.