48

I am a newbie to NextJS. It looks so good on the first impression. But after giving it a chance I have faced some problems like URL routing with custom params like react-router.

Currently what we can do with NextJS

https://url.com/users?id:123

What We need to have for better URL pattern

https://url.com/users/123

In react-router it has a perfect example here https://reacttraining.com/react-router/web/example/url-params

6 Answers 6

49

For anyone arriving late to this party, we now have dynamic routing in Next 9.

Which would allow for a url structure to be crafted like this by using the file structure, and without additional packages.

You could create a file pages/user/[id].js

With

import { useRouter } from 'next/router'

const User = () => {
  const router = useRouter()
  const { id } = router.query

  return <p>User: {id}</p>
}

export default User
Sign up to request clarification or add additional context in comments.

5 Comments

I am trying this but somehow router.query doesn't seem to return the id parameter. Can you please have a look at this stackoverflow.com/questions/62885756/…
Hi, the link to your question is broken. May I suggest you follow the online guide here: nextjs.org/learn/basics/dynamic-routes It covers what you ask about.
Hi, thanks for checking it out. it worked and it was some custom mistake so I deleted the question.
if i refresh the page, router.query become {} (empty), any clue why is it happening?
I would also include the state where the router has not loaded
23

For older version: < 9.x

You can use next/link's as feature:

<Link prefetch as={`/product/${slug}`} href={`/product?slug=${slug}`}>

Link on the browser will appear as /product/slug which internally maps to /product?slug=slug

You need to have a custom server for server-side mapping:

server.get("/product/:slug", (req, res) => {
  return app.render(req, res, "/product", { slug: req.params.slug })
})

For 9.x and higher

Next 9.x supports file system based dynamic routing. You don't need a custom server anymore.

Next.js supports creating routes with basic named parameters, a pattern popularized by path-to-regexp (the library that powers Express).

Creating a page that matches the route /product/:slug can now be achieved by creating a file in your pages directory named: pages/product/[slug].js.

Multiple dynamic URL segments are also supported!

./pages/blog/[blogId]/comments/[commentId].js
./pages/posts/[pid]/index.js

4 Comments

This is exactly the correct answer. After a bit more searching I found this is how they tell you to do it in their docs. nextjs.org/learn/basics/create-dynamic-pages and the following two sections explain it in detail.
And how to achieve this /product/:slug/:commentId?/:someOtherOptionalParam? into nextjs format?
@SirajAlam if you have optionals, you can use catch all routes. pages/product/[slug]/[...optionals].js matches /product/a, but also /product/a/b, /product/a/b/c and so on. Then you can split the optionals to get the commentId and other optionalParams.
@RashidulIslam, if you could answer this question with a bit explanation, I will mark you answer as accepted. stackoverflow.com/questions/62625134/…
12

Problem: query Object Always Empty

TL;DR: During first render, query is empty and Router.isReady is false. In all following render calls, everything is back to normal.

In recent versions, dynamic routing is fully supported. The docs even show a super simple example of how it works. Sadly, for some reason, the docs fail to mention the important issue of hydration. This blog post explains some extra details.

The gist is: in many dynamic rendering scenarios (including the default), during initial render on the client, the page first gets rendered without any parameters (probably due to hydration, based on a static state that cannot take the dynamic path into account).

Solution

Allow your component to "kinda work" even if router.query is empty, e.g.:

function MyComp() {
  const router = useRouter();
  const { id } = router.query;

  console.log(`[MyComp render] router.isReady=${router.isReady}, id=${id}`);

  useEffect(() => {
    if (!router.isReady) {
      return;  // NOTE: router.query might be empty during initial render
    }

    doSomethingWithData(id);
  }, [id, router.isReady]);

  if (!router.isReady) {
    // we are still waiting for dynamic data to be available
    return 'loading...';
  }

  return theActualContent;
}

There even is the crucial Router.isReady field that tells you whether query data is available, but, for some reason, they do not mention it in the Dynamic Routes documentation.

1 Comment

Yes, next js complains that about the client state
8

First import Router

import Router from 'next/router'

Then if you want to use it in a Link tag

<Link href={{ pathname: '/about', query: { name: 'Sajad' } }}>

If you want to use it in a function or after a callback

Router.push({
    pathname: '/about',
    query: { name: 'Sajad' },
  })

Comments

1

Updated answer for App router:

// app/users/[id].js;
'use client';
import { useParams } from 'next/navigation';

function UserDetails() {
  const { id } = useParams();
  return <div>User ID: {id}</div>;
}

export default UserDetails;

Docs: Next.js - useParams

1 Comment

Exact what I need. A lot more modern than upvoted answers. Thnx
0

To achieve the URL pattern https://url.com/users/123, where 123 is a dynamic parameter, you can use Next.js's built-in routing with parameterized routes.

First, create a file named [id].js inside the pages/users directory:

// pages/users/[id].js;
 import { useRouter } from 'next/router';

function UserDetails() {

const router = useRouter();
const { id } = router.query;

return <div>User ID: {id}</div>;
}
export default UserDetails;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.