NextJS: dynamic router.pathname does not show path, but filename - how to get words in path?
Asked Answered
C

5

13

I'm making this as simple of an example as possible, I can include more code later if it needs more info to be resolved

I'm using dynamic routes in nextJS. My app pulls results from twitter based on the keywords entered into the dynamic route via API using twitter-v2 package

I'm trying to use the words in the route using router.pathname in order to create some attributes on the page, but it uses the filename instead of the words in the url.

NextJS version: Next 9.5.3

Render page path: /pages/[keywords].jsx

Example url:

http://localhost:3000/kpop-heroes

example page function:

import { useRouter } from 'next/router'

export default function Keywords() {
  const router = useRouter();

  const KEYWORDS = router.pathname
    .slice(1)
    .split('-')
    .join(' ');

  return (
   <div>Twitter reactions to <code>{KEYWORDS}</code></div>
  )
};

Renders:

Pathname renders filename, not words typed in URL

Am I misunderstanding this feature? Is it possible to retrieve the words in the url instead of the filename?

Note: I've been using window.location.href as a workaround, but my understanding is accessing the window object is less than optimal

Christal answered 5/10, 2020 at 16:47 Comment(0)
T
19

Use the asPath property. It returns the path shown in the browser (including the query).

https://nextjs.org/docs/api-reference/next/router#router-object

const router = useRouter();

router.asPath
Tame answered 5/10, 2021 at 18:50 Comment(2)
This should be the accepted answer, router.asPath will resolve all the dynamic parts of the urlMerciless
In my case I was using router.asPath in a useEffect and it wouldn't resolve the dynamic parts, so I had to add router.isReady in the dependency array and check for it in the useEffect callback.Piton
D
5

To get correct URL for both cases e.g. dynamic ([slug]) and fixed path:

const router = useRouter();

let relativeURL = "";

  const slug = router.query.slug;
  if (slug) {
    relativeURL = router.pathname.replace("[slug]", slug as string);
  } else {
    relativeURL = router.pathname;
  }
Downey answered 29/9, 2021 at 19:27 Comment(0)
C
3

I was just using the wrong method - the correct method is router.query.

Consider the following url:

http://localhost:3000/test-keywords?query=params,%20strings,%20other%20things&anotherLevel=more%20stuff

log the object produced by the method:

  const router = useRouter();
  console.log(router.query);

output:

  {
    anotherLevel: "more stuff"
    keywords: "test-keywords"
    query: "params, strings, other things"
  }

I must've glossed over it, it's clearly in the docs right here: https://nextjs.org/docs/routing/dynamic-routes

Thought I'd leave this up in case someone else confused about it, too

Christal answered 6/10, 2020 at 6:42 Comment(0)
K
0

I think the right way is define the dynamic-routes under a specific path (ex. /twitter).

Render page path:

/pages/twitter/[keywords].jsx

Example url:

http://localhost:3000/twitter/kpop-heroes

It is unreasonable to define the dynamic-route at the first level of the url.

Kaka answered 6/10, 2020 at 3:6 Comment(1)
I've been using the first level just fine (?). I don't think it matters if it's in a subdir. Under 'caveats' nextjs.org/docs/routing/dynamic-routes says: Predefined routes take precedence over dynamic routes, and dynamic routes over catch all routes. I personally just have index.jsx in the pages dir, and anything else defaults to [keywords].jsxChristal
H
0

This worked for me

import { useRouter } from "next/router";

...

const router = useRouter();
const path = router.asPath.split("?")[0]; // (remove query string and use asPath since dynamic slug was rendering as "[slug]" using pathname)

...

 const navigationList = (
    <MenuList>
      {links.map((item) => {    
        return (
          <MenuItem
            key={item.id}
            disabled={path == item.href}
            sx={{
              m: 0,
              p: 0,
              ...(path == item.href && {
                borderBottom: `1px solid ${theme.palette.primary.light}`,
                backgroundColor: theme.palette.primary.dark,
              }),
            }}
          >
            <StyledLink href={item.href}>{item.label}</StyledLink>
          </MenuItem>
        );
      })}
    </MenuList>
  );
Hydrometeor answered 15/11, 2022 at 19:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.