Use NProgress with Next.js (Router and fetch events)
Vincent Voyer
Posted on June 9, 2020
Today I was trying to add NProgress https://github.com/rstacruz/nprogress to my Next.js project.
I wanted the progress bar to:
- show when switching routes / pages
- show when any fetch call is made
- display only after a delay, I don't want to show a loader at EVERY interaction, only when the requests are "slow"
Here's a demo of how NProgress
looks like:
Since I hit met some challenges while implementing all of that, I felt like it would be good to share how I did it. So here it is:
First, install the nprogress
package:
npm install nprogress
Then edit or create your _app.js
and add:
// global styles are required to be added to `_app.js` per Next.js requirements.
import "nprogress/nprogress.css";
const TopProgressBar = dynamic(
() => {
return import("components/TopProgressBar");
},
{ ssr: false },
);
export default function MyApp({ Component, pageProps }) {
return <>
<TopProgressBar />
<Component {...pageProps} />
</>
}
Here we use dynamic imports and the ssr option to make sure our TopProgressBar
is loaded only in browser environements.
If you're wondering how relatively loading components/TopProgressBar
works, just configure you jsconfig.json
as shown in the Next.js documentation.
Finally create components/TopProgressBar.js
:
import Router from "next/router";
import NProgress from "nprogress";
let timer;
let state;
let activeRequests = 0;
const delay = 250;
function load() {
if (state === "loading") {
return;
}
state = "loading";
timer = setTimeout(function () {
NProgress.start();
}, delay); // only show progress bar if it takes longer than the delay
}
function stop() {
if (activeRequests > 0) {
return;
}
state = "stop";
clearTimeout(timer);
NProgress.done();
}
Router.events.on("routeChangeStart", load);
Router.events.on("routeChangeComplete", stop);
Router.events.on("routeChangeError", stop);
const originalFetch = window.fetch;
window.fetch = async function (...args) {
if (activeRequests === 0) {
load();
}
activeRequests++;
try {
const response = await originalFetch(...args);
return response;
} catch (error) {
return Promise.reject(error);
} finally {
activeRequests -= 1;
if (activeRequests === 0) {
stop();
}
}
};
export default function () {
return null;
}
Here we register to Next.js router events and monkey patch the global fetch. I was worried monkey patching fetch
would fail to register early on but turns out it works 🤷♂️!
As you can see, TopProgressBar
renders nothing, I guess there might be issues of doing things this way so if you encounter some, just let me know!
That's it!
If you're wondering if NProgress
is still maintained because of the low number of commits and "high" number of issues, the good news is that they are working on a new version for 2020: https://github.com/rstacruz/nprogress/pull/218
Even if you're not using Next.js, you should be able to adapt this code to your favorite platform or framework.
Posted on June 9, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.