Search code examples
javascriptnode.jsreactjsnext.jsnavbar

usePathname() returning null AND useRouter() causing "Error: NextRouter not mounted" and "Error: invariant expected app router to be mounted" errors


I'm using NextJS version 13.4.4, and I've been trying to implement active navlinks. The issue is that for this solution, I want to access the current URL, but every attempt to do so ends up failing. My folder structure is like this:

  • .next
  • components
    • Header
      • header.tsx
      • navbar.tsx <<<< the file i'm working in
  • pages //my pages are here ...

my navbar code looks like this:

'use client'

import React from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/router';

export const Navbar = (props:any):JSX.Element =>{
    const links = [
        {
            path: "/",
            name: "Home"
        },
        {
            path: "/about", 
            name: "Resume"
        },
        {
            path: "/projects",
            name: "Projects"
        },
        {
            path: "/contact",
            name: "Contact Me"
        }
    ];

    const router = useRouter();
    const url = usePathname();
    //const url = router.pathname;

    return(
        <nav className="navbar navbar-dark navbar-expand-lg border-bottom topNav">
            <div className="container-fluid">
                <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                <span className="navbar-toggler-icon"></span>
                </button>
                <div className="collapse navbar-collapse justify-content-center w-100 mt-3 mt-lg-auto" id="navbarNav">
                    <ul className="navbar-nav justify-content-center">
                        {links.map((link, index):JSX.Element =>{
                            return(
                            <li className="nav-item px-5" key={index}>
                                <Link className={
                                    url === link.path ? "nav-link text-white navLink activeLink"
                                    : "nav-link text-white navLink"
                                    } aria-current="page" href={link.path}>{link.name}</Link>
                            </li>
                            )
                        })}
                    </ul>
                </div>
            </div>
        </nav>
    );
}

All suggestions welcome.

I've tried

import { useRouter } from 'next/router

export default Navbar = () =>{
   const router = useRouter();
   const url = router.pathname;
   ...
}

which results in my app crashing and the 'NextRouter not mounted' error.

I've tried

import { usePathname } from 'next/navigation'

export default Navbar = () =>{
   const url = usePathname();
   ...
}

which results in 'url' being null.

And I've also tried this just to see what options I have for getting the URL from this

import { useRouter } from 'next/navigation

export default Navbar = () =>{
   const router = useRouter();
   console.log(router)
   ...
}

which resulted in "Error: invariant expected app router to be mounted"

EDIT: After further reading, I discovered that my setup was quite janky. I was using Next 13+ features designed to play well with the app router, but my project was using the pages router. Of course, I could have made it work, but I felt that continuing with the pages router would involve lots of wasted effort doing simple things like this, so I decided to restructure my app to take advantage of the app router instead. Now everything works like clockwork.


Solution

  • Major changes

    • import { useRouter } from 'next/router'; ❌ Not supported in Nextjs 13.4
    • import { useRouter } from 'next/navigation'; ✅ supported in Nextjs 13.4

    For pathName not to be null you need to pass path using useRouter i.e

    import { useRouter } from 'next/navigation'; // important
    router = useRouter();
    router.push(pages/<your_page_here>);