Go back
Fixing href interpolation errors in Next.js
Jul 12, 2023 · 5 min read
For one, I honestly wouldn't think I'd ever come across this type of error below.
But, as I read through so many issues and discussions on GitHub, I began to understand why I ran into this error.
Normally, if you want to navigate to another page in Next.js, you'd need to use the link component like so:
<Link href="/path-to/where">Some text</Link>
And that's it. You won't need to worry about breaking what's not broken.
But, the situation was different for me.
Some days back I shared an opinion around keeping component state in the browser URL, and I have, before then, used this paradigm in most of my projects.
Ideally, I kept the state of a particular component in the URL, when it was time to navigate from the page where that component is currently in use — havoc wreaked! And the aforementioned error was thrown to my face!
I wept, and cussed as if it'd take away the despair that the error brought, Lol!
Anyway, in the error modal where the information about the error lies, was a link to a page on how to fix this interpolation error. Unfortunately, it did not work as it should.
Take a look at a similar snippet they recommended using.
Lest I forget, this error is predominant when you're working with dynamic routes in Next.js
import Link from 'next/link'
export default function SomePage() {
return (
<>
<Link
href={{
pathname: '/page/dynamic-segment/',
query: { slug: 'the dynamic segment' },
}}
>
Go to dynamic page
</Link>
</>
)
}
So, if you happen to keep state in the URL with query parameters, You'll modify the snippet above to look like the one below
import Link from 'next/link'
export default function SomePage() {
return (
<>
<Link
href={{
pathname: '/page/dynamic-segment?item=bag',
query: { slug: 'the dynamic segment', item: item },
}}
>
Go to dynamic page
</Link>
</>
)
}
Sometimes writing out the exact path can be difficult. Instead, you should append the pathname from next/router
like so:
<Link
href={{
pathname: router.pathname,
query: { slug: 'the dynamic segment', item: item },
}}
>
Go to dynamic page
</Link>
But, in all this, I did not use the <Link>
component. I used the push()
and replace()
methods of next/router
interchangeably because I thought that the Link
component could be buggy! Naive me!
So, the same action with the link component to navigate to another page became this, for me.
const { query } = useRouter()
const item = query
const handleNavigate = () => {
router.replace({
pathname: `/page/${dynamic_segment}?item=bag`,
query: { item: item },
})
}
Finally, a fix
I found solace in the fact that a lot of people shared this same grievance, after going through a lot of discussions and issues in the Next.js repo.
But, for how long? How long will I keep scouring through GitHub issues, discussions, and stackoverflow to no avail?
One particular stackoverflow answer stood out and gave me a clue as to how I could fix this. Adding a unique key that accepts the global router path as a value in _app.js
supposedly fixed the error.
import type { AppProps } from 'next/app'
import Head from 'next/head'
import React from 'react'
import { useRouter } from 'next/router'
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter()
return (
<>
<Head>
<title>Page Title</title>
</Head>
<Component {...pageProps} key={router.asPath} />
</>
)
}
But, why did this work?
Recall how we've always been told to add a key
prop to an element whenever we're performing a map()
operation on an array to let each item become a unique one.
The same approach applies here and here's why it worked:
When I tried navigating to a new dynamic route using the Link
component, Next.js recognized that the component instance was the same and tried to update its props.
This is wrong, it should not happen like that. So why did it behave that way? It did because the Link
component was not receiving any props that could uniquely identify it as a separate instance.
Since the component didn't have any distinct identification via a key
like we usually do to list items, Next.js might have not triggered a re-render of the component or properly updated the href interpolation.
By adding the key prop to the App component and setting it to router.asPath
, you're providing a unique identifier for each instance of the component.
router.asPath
represents the current URL path, which makes sure that when you navigate to a new page, a new instance of the App component is created.
This unique identifier — key
— helps Next.js recognize that a new instance of the App component is being rendered, and as a result, the Link component and its href interpolation are correctly initialized, avoiding the previous error.
Wrapping up
Since the Link
component uses the underlying principles of next/router
, even if you do not perform navigation with the Link
component, instead you decided to focus on router.push
or .replace()
this solution still applies to both approaches.