Next.js Router - Listen to route (location) change with useRouter
Tutorial built with Next.js 13
This is a quick post on how to detect route changes with Next.js Router to execute code on location change in a Next.js (React) client app.
There are a couple of ways to do it, with a useEffect dependency or with route change events.
- Detect route change with useEffect dependency: a React
useEffect()
hook function with the dependency array set to[router]
will execute on route change and when the component first loads. - Detect route change with router events: the Next.js router allows you to subscribe to route change events including
routeChangeStart
androuteChangeComplete
.
Below are examples of each approach.
Detect route change with Next.js [router]
dependency
This snippet shows how to listen to route change with Next.js router by passing the router
object in the dependency array of a useEffect()
hook function.
The callback function is executed when the component first loads and on route change, it simply increments a route change counter and a logs the current pathname to the console.
NOTE: With [router]
as the dependency the code will execute even if you navigate to the same page (e.g. if you click the Home
link from the home page). If you only want to execute only when changing to a different route use [router.pathname]
instead.
const router = useRouter();
// detect route change with useEffect dependency
const [count, setCount] = useState(0);
useEffect(() => {
setCount(x => x + 1);
console.log('route change with dependency', router.pathname);
}, [router]);
Detect route change with Next.js routeChangeStart
and routeChangeComplete
events
This snippet shows how to subscribe to the routeChangeStart
and routeChangeComplete
events of the Next.js router.
The useEffect
hook with an empty dependency array is executed once when the component is mounted. The return function is executed when the component is destroyed so is used to unsubscribe from the route change events to prevent memory leaks in the app. Named functions are used to enable unsubscribing.
The functions called on route change start and route change complete simply increment a counter for each event and log the current url to the console.
const router = useRouter();
// detect route change with router events
const [startCount, setStartCount] = useState(0);
const [completeCount, setCompleteCount] = useState(0);
useEffect(() => {
// subscribe to routeChangeStart event
const incrementStartCount = (url) => {
setStartCount(x => x + 1);
console.log('routeChangeStart', url);
};
router.events.on('routeChangeStart', incrementStartCount);
// subscribe to routeChangeComplete event
const incrementCompleteCount = (url) => {
setCompleteCount(x => x + 1);
console.log('routeChangeComplete', url);
};
router.events.on('routeChangeComplete', incrementCompleteCount);
// unsubscribe on component destroy in useEffect return function
return () => {
router.events.off('routeChangeStart', incrementStartCount);
router.events.off('routeChangeComplete', incrementCompleteCount);
}
}, []);
Next.js (React) component that listens to route (location) change
This is the complete Next.js (React) component that the above snippets are taken from, it includes a nav bar and a couple of routes to test the location change listeners.
You can see the code running and tinker with it yourself on StackBlitz at https://stackblitz.com/edit/nextjs-listen-to-route-change.
import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import Link from 'next/link';
import '../styles/globals.css';
export default App;
function App({ Component, pageProps }) {
const router = useRouter();
// detect route change with useEffect dependency
const [count, setCount] = useState(0);
useEffect(() => {
setCount(x => x + 1);
console.log('route change with dependency', router.pathname);
}, [router]);
// detect route change with router events
const [startCount, setStartCount] = useState(0);
const [completeCount, setCompleteCount] = useState(0);
useEffect(() => {
// subscribe to routeChangeStart event
const incrementStartCount = (url) => {
setStartCount(x => x + 1);
console.log('routeChangeStart', url);
};
router.events.on('routeChangeStart', incrementStartCount);
// subscribe to routeChangeComplete event
const incrementCompleteCount = (url) => {
setCompleteCount(x => x + 1);
console.log('routeChangeComplete', url);
};
router.events.on('routeChangeComplete', incrementCompleteCount);
// unsubscribe on component destroy in useEffect return function
return () => {
router.events.off('routeChangeStart', incrementStartCount);
router.events.off('routeChangeComplete', incrementCompleteCount);
}
}, []);
return (
<div>
<nav className="navbar navbar-expand navbar-dark bg-dark px-3">
<div className="navbar-nav">
<Link href="/" className="nav-item nav-link">Home</Link>
<Link href="/about" className="nav-item nav-link">About</Link>
</div>
</nav>
<div className="container pt-4 pb-4">
<Component {...pageProps} />
<hr />
<ul>
<li>Route change count with useEffect dependency: {count}</li>
<li>routeChangeStart event count: {startCount}</li>
<li>routeChangeComplete event count: {completeCount}</li>
<li>Current route: {router.pathname}</li>
</ul>
</div>
</div>
);
}
Need Some NextJS Help?
Search fiverr for freelance NextJS developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!