How to Listen to URL Changes in Next.js for a Route or Overall App

Nitish Kumar Singh

Nov 23, 2023

Hello Developers, In this blog post, we will see how to listen to URL changes at the route level or application level in a Next.js app. We will create a listener to listen for URL changes in both App Router and Pages Router.

Photo by Thom Holmes on Unsplash

To listen for URL changes, we use hooks and create components that handle all the things. So, we use the following hooks for both Routers:

  • Pages Router: In Pages Router, we use useRouter from next/router and useEffect from react with router as a dependency.
  • App Router: In App Router, we use usePathname from next/navigation and useEffect from react with pathname as a dependency.

Basically, we need a listener at the route level if the route is a dynamic route because once you navigate to that route and change the path of the browser URL by links or using the router object, we need a listener. For example, when I am creating a search form and a search route that shows search results, here I need it. You can see it on my movie streaming website.

Listen to URL Changes in Pages Router

At Route Level

In Pages Router, to listen to URL changes at the route level of a dynamic route, we create a React functional component that takes a function as props to notify the parent route component of URL changes and use hooks for listening. And render this component in that route component for which we want to listen to URL changes. So the following code is an example of a Listener component to listen at the route level:

import { useRouter } from 'next/router'
import { useEffect } from 'react'

export default function Listener({onUrlChange}) {
    const router = useRouter();
    useEffect(()=>{
        // Get path that showing on browser url
        console.log(router.asPath);
        // Get query object and query parameter.
        console.log(router.query.collection);
        // notify dynamic(parent) route with path
        onUrlChange(router.asPath);
    },[router,onUrlChange]);
  return ("")
}

Here I have created a dynamic route by naming the folder [collection], so getting the query (or what you say it) as the collection property of the query object.

Render the above component in that dynamic (parent) route like showing in the below code:

import Listener from "...";

export default class Collection extends Component {
  onUrlChange = (pathname)=>{
    console.log(pathname);
  }
  render() {
    return (
      <>
         <Listener onUrlChange={this.onUrlChange}/>
         {/* below your rest of jsx*/}
         ....
      </>
    )
  }
}

I use it in a class component, but you can also use it in functional components.

At Application Level

To listen at the application level, we create a GlobalListener like the previous listener, just here change notifying code and render it in the _app component.

The following code is an example of that component:

import { useRouter } from 'next/router'
import { useEffect } from 'react'
export const listners = {};
export default function GlobalListener() {
    const router = useRouter();
    useEffect(()=>{
        const pathname = router.asPath;
        for (const key in listners) {
            listners[key](pathname);
        }
    },[router]);
  return ("")
}

And render it in the _app component like below:

import '@/styles/globals.css'
mport GlobalListener from './Componets/Listener';

export default function App({ Component, pageProps }) {
  return (
    <>
    <GlobalListener/>
    <Component {...pageProps} />
    </>
  )
}

Whenever we need to listen for URL changes in a route or component, then attach a listener (function) with a unique name like below:

import { listners } from './Componets/Listener';

const onUrlChange = (pathname)=>{
   console.log(pathname);
}
    
listners.hello = this.onUrlChange;

And make sure to remove it if not needed like below:

// in class component
componentWillUnmount(){
    delete listners.hello;
}

Listen to URL Changes in App Router

In App Router, we do all things the same as doing for Pages Router, just change a few things like below:

  • First of all, we use the "use client" directive in the Listener component.
  • For listening to URL changes, we use usePathname from next/navigation and useEffect from react with pathname as a dependency.
  • And render it in layout.js file for global (app level) listening.

So the following code is an example of the listener for listening at the route level in App Router:

'use client';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react'
export default function Listener({onUrlChnage}) {
    const pathname = usePathname();
    useEffect(()=>{
        onUrlChnage(pathname);
    },[pathname]);
  return ("")
}

And for application level:

'use client';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react'
export const listners = {};
export default function GlobalListener() {
    const pathname = usePathname();
    useEffect(()=>{
        for (const key in listners) {
            listners[key](pathname);
        }
    },[pathname]);
  return ("")
}

Render it in layout.js file of the app directory like below:

import "./globals.css";
import GlobalListener from "....";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <GlobalListener/>
        <div id="root">
           {children}
        </div>
      </body>
    </html>
  );
}

Attach and detach listeners the same as Pages Router.

I hope you learn how to listen for URL changes in Next.js and enjoy reading this blog post. Feel free to modify the above codes as your requirements. I just described what I created and used on my movie streaming site.

Published on Nov 23, 2023
Comments (undefined)

Read More

How to Remove All Child Elements at Once in JavaScript

Hello, developers! In this blog post, we will learn how to remove all child elements at once from an HTML element using JavaScript. Removing all children at once is a little problematic task on the web because the web does not have any method like removeAll() that removes all children.

Nov 17, 2023

How to Hover on a Child Element Without Hovering on the Parent, Using Only CSS

Hello, developers! In this blog post, we will learn "How to hover on a child element without hovering on the parent, using only CSS". I mean adding some style to the child element when hovering over it, following the conditions below:

Nov 7, 2023

How to Control Volume using Android SeekBar in Java

Hello Developers! In this blog post, we will learn how to change volume using SeekBar in Android using Java. Basically we increase or decrease system volume of phone when progress of SeekBar chnages and show a TextView for volume level.

Nov 15, 2023

How to Change Brightness of Only One Activity in Android Using Java

Hello Developers! In this blog post, we will learn how to change the brightness of only one activity, not for the overall application or the entire phone brightness. For example, if the user drags on the screen, changes the progress of the seek bar, or clicks on buttons, then the brightness of the activity should change. This is a feature commonly seen in Video-Player Apps.

Nov 13, 2023

How to Convert Milliseconds Time into Formatted String (HH:MM:SS) in Java

Hello Developers! in this blog post, we will learn how to convert milliseconds time into formatted String in Java. For example 6548000 milliseconds into 1:49:08, so we can show it as duration to user.

Nov 12, 2023

How to create Toast or Snackbar using CSS and JavaScript

Hello Developers! In this blog post, we will create a Toast or Snackbar using CSS and JavaScript to show a short-duration, non-interactive message to the user upon an action. We will design the Toast to be versatile, serving as an informational, warning, error, or success message by utilizing different colors for each message type. Additionally, we'll explore the customization of the Toast's position on the screen.

Nov 10, 2023