Get URL Params (Next.js 13)
Asked Answered
H

8

32

I am building a Next.js 13 project with the /app directory. I have a problem - in the root layout, I have a permanent navbar component in which the component is imported from /components/Navbar.jsx. Basically inside the Navbar.jsx, I want to be able to access the slug parameter in url, for ex: localhost:3000/:slug in which I want the slug id. I have already defined a Next.js 13 page.jsx for that slug. But how do I get the slug id in the navbar component. I also don't want to use window.location.pathname because it doesn't change when the page routes to a different slug and only does when I refresh.

I have tried the old Next.js 12 method:

//components/navbar.jsx;

import { useRouter } from "next/navigation";

export default function Navbar () {
  const router = useRouter();
  const { slug } = router.query;

  useEffect(() => {
    console.log(slug);
  }, []);

  return <p>Slug: {slug}</p>
}

However it does not work.

Hoke answered 26/11, 2022 at 8:27 Comment(1)
Does this answer your question? How can I get (query string) parameters from the URL in Next.js?Doorplate
D
27

There are 3 different variants of params

  1. params (/blog/1)
    • single params
    • multiple params
  2. searchParams (/blog?postId=123)
    • single search params
    • multiple search params
  3. Both params and searchParams (/blog/1?postId=123)

There are multiple ways to handle this

  1. For params - useParams()
'use client'
 
import { useParams } from 'next/navigation'
 
export default function ExampleClientComponent() {
  const params = useParams()
 
  // Route -> /shop/[tag]/[item]
  // URL -> /shop/shoes/nike-air-max-97
  // `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
  console.log(params)
 
  return <></>
}
  1. For searchParams - useSearchParams()
'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function SearchBar() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')
 
  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>
}
  1. Both params and search Params using any type
'use client'

export default function BlogPost(props: any) {

    // URL -> blog/a/b?param1=IamfirstParam&param2=IamsecondParam
    return <div>{props}</div>;

   // Output ->
   //{
   //  params: { blogId: [ 'a', 'b' ] },
   //  searchParams: { param1: 'IamfirstParam', param2: 'IamsecondParam' }
   //}
}
  1. Both params and search Params using defined type
'use client';

// URL -> blog/a/b?param1=IamfirstParam&param2=IamsecondParam

export default function BlogPost({
    params,
    searchParams,
}: {
    params: { blogId: string[] };
    searchParams: { param1: string; param2: string };
}) {


    return (
        <div>
            {params.blogId[0]}
            {params.blogId[1]}
            {searchParams.param1}
            {searchParams.param2}
        </div>
    );
}

For all possibility of dynamic params refer: How to do dynamic routes with Next.js 13?


Also refer to the latest Next.js 13 code templates Next.js 13+ Power Snippets | TypeScript/Javascript

It includes wide range of code snippets for both ts and js. Find all snippets here

Doorplate answered 4/7, 2023 at 14:27 Comment(1)
It's not necessary to only do all of this from client components. We can still reap the benefits of server components in any page file.Backup
I
25

To get the URL parameters in a Server Component in Next.js 13, you can use the searchParams argument of the Page function.

URL

localhost:3000/?slug

/app/page.js

export default function Page({searchParams}) {
   return <Navbar slug={searchParams}></Navbar>
}

navbar.js

export default function Navbar(props) {
   return <p>Slug: {props.slug}</p>
}

More info: https://beta.nextjs.org/docs/api-reference/file-conventions/page

Isocyanide answered 25/12, 2022 at 20:54 Comment(2)
How can we type this?Indre
For route.js, use req.nextUrl.searchParams. The req is a NextRequest object that is past as the first parameter to for example the GET function ie export async function GET(req: NextRequest) {Nilotic
S
13

Another way is to use the hook useSearchParams.

From the documentation:

import { useSearchParams } from 'next/navigation';

export default function Page() {
  const searchParams = useSearchParams();

  // E.g. `/dashboard?page=2&order=asc`
  const page = searchParams.get('page');
  const order = searchParams.get('order');

  return (
    <div>
      <p>Page: {page}</p>
      <p>Order: {order}</p>
    </div>
  );
}
Stringpiece answered 11/2, 2023 at 18:20 Comment(2)
useSearchParams requires client side component, it doesn't work in server side componentAgnail
Thank you this worked for me, I was looking for a client sided get param. <3Petree
D
10

I don't know if the question is still relevant but you can use NextRequest included methods nextUrl.searchParams.get or getAll if it's an array.

import { NextResponse, NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  
  const queryParam = request.nextUrl.searchParams.get("queryParam");
  
  return NextResponse.json({ message: 'Query parameter value is ' + queryParam }, { status: 200 });
}

I used it in an endpoint but the same goes for pages, must warn that NextRequest can only be used in server components, for client ones you need useRouter with the 'use client'.

Dwayne answered 2/6, 2023 at 13:32 Comment(0)
H
6

In order to get params and searchParams in server side component using typescript in Next.js 13, you should define what params and searchParams do you expect. For example:

// /app/category/[slug]/page.tsx
// Request URL localhost:3000/category/news?page=2

export default function PostsCategory({ params, searchParams }: { params: { slug: string }; searchParams: { page: string } }) {
  const posts = getPostsByTag(params.slug, ['title', 'date', 'excerpt', 'image', 'slug', 'tags']);
  const currentPage = searchParams && searchParams.page ? Number(searchParams.page) : 1;
  const { slug } = params;

  return (
    <main>
      <PaginatedPosts posts={posts} page={currentPage} title={`${slug}`} />
    </main>
  );
}
Hypethral answered 9/7, 2023 at 17:37 Comment(5)
THANK YOU! I feel like this is a pretty common use-case yet it's pretty hard to find in the current Next.js docs if you don't know to search for searchParams (ironically).Disforest
How about layouts? The question is about the layout and its components?Takeshi
@mmomtchev But why would you even need to check for searchParams in layout as the layout applies to everything underlying. In my opinion if you are using the same search params down the structure then you have something wrong in app architecture of app. For example (?param=1, /blog?param=1, /blog/post?param1), this doesn't make much sense, each page has or [slug] page have unique set of params.Agnail
@mmomtchev and same goes for components (reusable part of the code), you don't know which page they will belong to (yes, you may know it and use it only on one place but for example Pagination component should not be owner of data, it should handle page changes and relevant calls but to make it reusable data has to come from top of hierarchy - in this case page)Agnail
You didn't see my answer belowTakeshi
H
4

Had to use usePathname

import { usePathname } from 'next/navigation';
Hoke answered 26/11, 2022 at 8:37 Comment(0)
T
2

The official docs are very clear on this: https://nextjs.org/docs/app/api-reference/functions/use-search-params#server-components

Pages

To access search params in Pages (Server Components), use the searchParams prop.

Layouts

Unlike Pages, Layouts (Server Components) do not receive the searchParams prop. This is because a shared layout is not re-rendered during navigation which could lead to stale searchParams between navigations.

Instead, use the Page searchParams prop or the useSearchParams hook in a Client Component, which is re-rendered on the client with the latest searchParams.

So simply make a small client component that will be re-rendered at every navigation and reference it from your layout.

Takeshi answered 30/8, 2023 at 19:26 Comment(1)
Precisely. Or, restructure such that you can just get this in a page.Backup
M
0
  • If your Navbar is a server component, you can try to pass params from the parent component. In Nextjs 13, Page and Layout will have a params field in props that indicates params of URL. You can have a look at this doc. Example:

    export default async function Page({params}) {
          const { slug } = params;
    
      return <Navbar slug={slug} />
    }
    
    export default async function Navbar ({ slug }) {
      return <p>Slug: {slug}</p>
    }
    
  • If you use any hook like useParams hook. The component will become a client component at runtime.

Monition answered 3/1 at 21:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.