0

Problem Statement: In NextJS 13 with app router, I want to pass data from "/experimental" to dynamic route "/experimental/${id}". It gives me 'router.query' as it is undefined. Is there any better approach?

I tried using 'next/navigation' in the nextjs 13 with app router. I can't pass the data to one component to another.

Here is my Json data

draft.js

export const draft = [
  {
    id: 1,
    title: "Burkina Faso serve Togo Vincent student",
    imageUrl: "/cards/1.jpg",
    imageType: "single image",
    price: 8000,
    buttonText: "View Design",
    cardType: "Single Page",
    popularity: 1,
    cardCategory: "singlePageCard",
  },
];

export default draft;

Here is my ExperimentCard where I pass and mapping the Draft.js data object

import Cards from "../../components/Cards/Cards";
import { draft } from "../../Data/Draft_Data";

const ExperimentalCard = () => {
  return (
    <div className="ml-[1rem] md:ml-14">
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-y-10 min-h-[120vh]">
        {draft.map((item, index) => (
          <Cards key={index} items={item} />
        ))}
      </div>
    </div>
  );
};

export default ExperimentalCard;

And the Card components will like this. And From Cards Components I want to pass data to dynamic route "/experimental/${id}".

Cards.jsx

'use client'
 
import { useRouter } from 'next/navigation'
import React from "react";

const Cards = ({ items }) => {

  const router = useRouter()
  
  const handleCardClick = (id) => {
    router.push(`/experimental/${id}`);
  };

  return (
    <div>
      
        <div className="mx-5  lg:mx-10">
          <div
            className="w-full h-[30rem] md:h-[25rem]  lg:h-[20rem] items-center bg-contain bg-no-repeat"
            style={{ backgroundImage: `url('${items.imageUrl}')` }}
            onClick={() => handleCardClick(item.id)}
          >
            <div className="bg-[#23272a93] relative z-0 w-32 mb-4 ml-4 h-11 text-center items-center flex rounded-sm justify-center ">
              <p className="text-base-100 uppercase">{items.cardType}</p>
            </div>
          </div>
          <div className="flex flex-row mt-4 justify-between">
            <h2 className="font-normal text-[1.5rem] md:text-[1.4rem] lg:text-xl basis-2/3">
              {items.title}
            </h2>
            <p className="font-bold text-2xl lg:text-xl basis-1/3 text-right md:text-left lg:text-right">
            ৳{items.price}
            </p>
          </div>
          {/* <p>Popularity: {items.popularity}</p> */}
        </div>
   
    </div>
  );
};

export default Cards;

When I click the component it will navigate to the dynamic link "/experimental/${id}". It gives me an error

[id]/page.jsx

'use client'
import { useRouter } from 'next/navigation'
import React from 'react'

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

  return (
    <div>
      <h1>Experimental Card Details</h1>
      <p>Card ID: {id}</p>
      <p>Card title: {title}</p>
      <p>Card imageUrl: {imageUrl}</p>
      <p>Card imageType: {imageType}</p>
      <p>Card price: {price}</p>
      <p>Card buttonText: {buttonText}</p>
      <p>Card cardType: {cardType}</p>
      <p>Card popularity: {popularity}</p>
      <p>Card cardCategory: {cardCategory}</p>
    </div>
  );
}

export default Page

Unhandled Runtime Error TypeError: Cannot destructure property 'id' of 'router.query' as it is undefined.

src\app\experimental\[id]\page.jsx (7:10) @ id

   5 | const Page = () => {
   6 | const router = useRouter();
>  7 | const { id } = router.query; 
     |        ^
   8 | 
   9 | return (
  10 |   <div>
Auvee
  • 95
  • 2
  • 15

3 Answers3

1

This is how I handle params and queries in the App router

your case

export default async function Page({
  // your dynamic value in this case [id]
  params 
})

In case you have searchParams eg [id]?ref=foo-bar

typescript:

export default async function Page({
  // dynamic route params
  params,
  searchParams,
}: {
  // [id] in your case
  params: { id: string };
  searchParams: { ref: string };
})

Check the NextJs documentation for details

You implementation should be like this

// note that this will be a RSC, therefore no need for 'use client' directive
import React from 'react'

const Page = ({ params }) => {
  const id = params.id 

  return (
    <div>
      <h1>Experimental Card Details</h1>
      <p>Card ID: {id}</p>
    </div>
  );
}

export default Page
Fer Toasted
  • 1,274
  • 1
  • 11
  • 27
1

router in next/navigation doesn't support query parameter. Use useParams instead.

Invoke as

<Link href={"/experimental/123"}>
    button
</Link>

Receive as

export default function Page({ params }: { params: { id: string } }) {
    return <h1>{params.id}</h1>;
 } 

Also refer

  1. https://stackoverflow.com/a/76609568/13431819
  2. https://stackoverflow.com/a/76613628/13431819
krishnaacharyaa
  • 14,953
  • 4
  • 49
  • 88
  • How can pass all items(tittle, description, price)? – Auvee Jul 12 '23 at 18:32
  • You can use multiple parameters as in the above shared link . If you are looking for sending it as a whole, unfortuantely it's not possible presently, find my similar question here https://stackoverflow.com/q/76661066/13431819 – krishnaacharyaa Jul 12 '23 at 19:13
  • But I only want to pass the data that are already destructor in the cards.jsx. I want to pass that data to my page.jsx dynamically – Auvee Jul 12 '23 at 22:22
  • Please explain the complete scenario by editing the question, it's very unclear what is your requirement, so that I can better assist – krishnaacharyaa Jul 13 '23 at 02:47
  • Why do you need query ? You are not passing query but you are expecting value from query that's the problem. – krishnaacharyaa Jul 13 '23 at 13:09
  • Is there any better way? Please eloborate me. – Auvee Jul 13 '23 at 13:23
  • Any other possible solution would suffice. And Please show me the implementation – Auvee Jul 13 '23 at 13:24
  • @Auvee you will get your required answer if you go through the above 2 links, you are not passing any query and you are trying to get value of query. You need to use useParams() as shown in the link given above. Please find the detailed answer there. If you want only to the point refer the above answer. – krishnaacharyaa Jul 13 '23 at 14:58
1

I solved it with useParams in

"[id]/page.jsx" -> component,
"experimental/${id}" -> route

I just get the id from the Route then perform find operation in my local json to get the single card data.

Here is my Dynamic Route Code for [id]/page.jsx

"use client";

import React from "react";
import { draft } from "../../../Data/Draft_Data";
import { useParams } from "next/navigation";

const Page = () => {
  const params = useParams();
  const card = draft.find((item) => item.id === parseInt(params.id));

  return (
    <div>
      <h1>Experimental Card Details</h1>
      {card ? (
        <>
          <p>Card ID: {card.id}</p>
          <p>Card title: {card.title}</p>
        </>
      ) : (
        <p>Card not found.</p>
      )}
    </div>
  );
};

export default Page;
Auvee
  • 95
  • 2
  • 15