NextJS URL params like React-Router
Asked Answered
D

6

43

I'm a newbie to NextJS, It looks so good on the first impression. But after giving it a chance I've 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 perfect example here https://reacttraining.com/react-router/web/example/url-params

Deficit answered 3/4, 2017 at 9:57 Comment(0)
S
44

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
Subtractive answered 12/9, 2019 at 15:21 Comment(4)
I am trying this but somehow router.query doesn't seem to return the id parameter. Can you please have a look at this #62886256Raillery
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.Subtractive
Hi, thanks for checking it out. it worked and it was some custom mistake so I deleted the question.Raillery
if i refresh the page, router.query become {} (empty), any clue why is it happening?Thema
K
22

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
Karen answered 28/3, 2018 at 2:9 Comment(4)
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.Phenobarbitone
And how to achieve this /product/:slug/:commentId?/:someOtherOptionalParam? into nextjs format?Canaletto
@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.Karen
@RashidulIslam, if you could answer this question with a bit explanation, I will mark you answer as accepted. #62625634Canaletto
S
9

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.

Sancho answered 2/7, 2022 at 16:43 Comment(0)
C
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' },
  })
Curvet answered 24/9, 2019 at 6:25 Comment(0)
U
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;
Unguinous answered 14/8, 2023 at 10:54 Comment(0)
S
0

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

Satirical answered 17/5, 2024 at 19:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.