Next JS dynamic Routing based on clicked item ID

72 Views Asked by At

I am trying to create a website where the main page is showing list of card containing information of a restaurant

i tried to create folder named "detail" containing [id].jsx. this is the code for [id].jsx

export const getStaticPaths = async () => {
  const res = await fetch(`https://restaurant-api.dicoding.dev/list`);
  const data = await res.json();

  const paths = data.map((restaurant) => {
    return {
      params: { id: restaurant.id },
    };
  });

  return {
    paths,
    fallback: true,
  };
};

export const getStaticProps = async ({ params }) => {
  const id = params.id;
  const res = await fetch(`https://restaurant-api.dicoding.dev/detail/${id}`);
  const data = await res.json();

  console.log(data);
  return {
    props: { restaurant: data },
  };
};

const Details = ({ restaurant }) => {
  return (
    <div>
      <h1>{restaurant.name}</h1>
      <p>{restaurant.email}</p>
      <p>{restaurant.website}</p>
      <p>{restaurant.address.city}</p>
    </div>
  );
};

export default Details;

this is where i tried to access [id].jsx

"use client";
import { RestaurantCard } from "../components/card";
import { getRestaurants } from "../hooks/UseGetRestaurants";
import Link from "next/link";

export default function ListRestaurant() {
  const data = getRestaurants();

  if (!data || !data.restaurants) {
    return null;
  }

  return (
    <>
      <div className="grid grid-cols-4 gap-3">
        {data.restaurants.map((item, index) => (
          <Link href={`/detail/${item.id}`} key={item.id}>
            <RestaurantCard
              image={item.pictureId}
              name={item.name}
              city={item.city}
              key={item.id}
              rating={item.rating}
            />
          </Link>
        ))}
      </div>
    </>
  );
}

but it always shows not found. i tried to use hooks but the result is the same. what am i missing?

1

There are 1 best solutions below

0
On

Problem :

i tried to create folder named "detail" containing [id].jsx. this is the code for [id].jsx.....but it always shows not found. i tried to use hooks but the result is the same. what am i missing?

Expected Output :

  1. Homepage, showing all restaurants.
  2. Homepage/detail/restaurantID = get restaurant details by ID & show details

Possible Cause:

Improper Folder Structure, in app router you have to keep folder name as [id] & inside it a page.js

Solution:

Folder Structure should be :

projectName
├── src
│   └── app
│       ├── detail    //folder
│       │   └── [restaurantID]    //folder
│       │       └── page.js   // homepage/detail/restaurantID
│       ├── favicon.ico
│       ├── globals.css
│       ├── layout.js
│       ├── not-found.js
│       ├── page.js   // homepage

Here's a small example code :

page.js at projectName\src\app\page.js :

import Link from "next/link";
async function GetRestaurants() {
  const res = await fetch(`https://restaurant-api.dicoding.dev/list`);
  const data = await res.json();
  return data

};


export default async function Home() {

  let data = await GetRestaurants()


  return (
    <main className="p-24">
      <h1>Homepage</h1>
      <div>
        <h3>Restaurants</h3>

        <ol >
          {
            data.restaurants.map((item, index) => (
              <li key={item.id}>
                <Link href={`/detail/${item.id}`} >
                  {item.name} {item.city} {item.rating}
                </Link>
              </li>
            ))
          }

        </ol>
      </div>
    </main>
  )
}

details page at projectName\src\app\detail\[restaurantID]\page.js :

async function GetRestaurantsDetailsByID(params) {
    const id = params.restaurantID;
    const res = await fetch(`https://restaurant-api.dicoding.dev/detail/${id}`);
    const data = await res.json();
    return data.restaurant
};

const DetailsPage = async ({ params }) => {
    let data = await GetRestaurantsDetailsByID(params)
    return (
        <div>
            Restaurant Details for ID : {params.restaurantID}
            <div>
                <h1>{data.name}</h1>
                <p>{data.email}</p>
                <p>{data.website}</p>
                <p>{data.description}</p>
                <p>{data.city}</p>
                <p>{data.address}</p>
            </div>
        </div>
    )
}

export default DetailsPage

This way you can get desired output.

Other problems : getStaticProps getStaticPaths & getServerSideProps this are available in Page Router.

Please Read :

  1. Convention : https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#convention
  2. Static Rendering : https://nextjs.org/docs/app/building-your-application/rendering/server-components#static-rendering-default
  3. Fetching Data on the Server with fetch : https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#fetching-data-on-the-server-with-fetch
  4. Generating Static Params : https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#generating-static-params
  5. Roles of Folders and Files : https://nextjs.org/docs/app/building-your-application/routing#roles-of-folders-and-files

If you still have any doubts, please leave a comment. If this answer is helpful you may mark it is answer.