18

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.

Vivaan Kumar
  • 457
  • 3
  • 4
  • 9
  • 1
    Does this answer your question? [How can I get (query string) parameters from the URL in Next.js?](https://stackoverflow.com/questions/43862600/how-can-i-get-query-string-parameters-from-the-url-in-next-js) – krishnaacharyaa Jul 04 '23 at 14:29

7 Answers7

15

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

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

Alexis Breton
  • 389
  • 3
  • 7
10

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>
  );
}
Daniel Boyer
  • 371
  • 3
  • 18
5

There are 3 different varients 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 searchParmas (/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 possiblity of dynamic params refer: How to do dynamic routes with nextjs 13?


Also refer latest Nextjs 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


krishnaacharyaa
  • 14,953
  • 4
  • 49
  • 88
  • There is no reason to 'use client' as you can get params in server side component – Ondřej Ševčík Jul 09 '23 at 17:30
  • 2
    @OndřejŠevčík, in official docs it says `useParams` is a Client Component hook that lets you read a route's dynamic params filled in by the current URL. Kindly refer https://nextjs.org/docs/app/api-reference/functions/use-params – krishnaacharyaa Aug 06 '23 at 15:20
  • As per official documentation using server component is always preferred, so your advice is wrong – Ondřej Ševčík Aug 09 '23 at 08:04
4

I don't know if the question is still relevant but you can use NextRequest included methods nextUrl.searchParams.get or getAll if its 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'

3

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>
  );
}
ash
  • 3
  • 1
Ondřej Ševčík
  • 1,049
  • 3
  • 15
  • 31
  • 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). – djflorio Aug 30 '23 at 14:05
  • How about layouts? The question is about the layout and its components? – mmomtchev Aug 30 '23 at 19:23
  • @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. – Ondřej Ševčík Aug 31 '23 at 15:04
  • @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) – Ondřej Ševčík Aug 31 '23 at 15:06
  • You didn't see my answer below – mmomtchev Aug 31 '23 at 15:17
2

Had to use usePathname

import { usePathname } from 'next/navigation';
Vivaan Kumar
  • 457
  • 3
  • 4
  • 9
0

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.

mmomtchev
  • 2,497
  • 1
  • 8
  • 23