cajie
cajie

Reputation: 33

NextJs nested dynamic routes based on API

I am stuck with Nextjs : I need to create nested dynamic routes based on my (local) data.

Here are the routes that I would like to create :

  1. .../cars/ -> displays all the categories (sedan, suv, 4x4)

  2. .../cars/category/ -> displays cars in the category

    ex : .../cars/sedan -> displays cars in the sedan category

  3. .../cars/category/id -> displays the details of the car from category which has id = 1

    ex : .../cars/sedan/1 -> displays the details of the sedan car with id = 1

For routes 1 and 2 it's ok but I don't know how to do the last one. Can you help me please ?

data.js

export const cars = [
  {
    id: 1,
    name: 'sedan',
    models: [
      {
        id: 1,
        name: 'model1',
        image: '/sedan1.jpg',
      },
      {
        id: 2,
        name: 'model2',
        image: '/sedan2.jpg',
      },
      {
        id: 3,
        name: 'model3',
        image: '/sedan3.jpg',
      },
    ],
  },
  {
    id: 2,
    name: 'suv',
    models: [
      {
        id: 1,
        name: 'model1',
        image: '/suv1.jpg',
      },
      {
        id: 2,
        name: 'model2',
        image: '/suv2.jpg',
      },
      {
        id: 3,
        name: 'model3',
        image: '/suv3.jpg',
      },
    ],
  },
  {
    id: 3,
    name: '4x4',
    models: [
      {
        id: 1,
        name: 'model1',
        image: '/4x4_1.jpg',
      },
      {
        id: 2,
        name: 'model2',
        image: '/4x4_2.jpg',
      },
      {
        id: 3,
        name: 'model3',
        image: '/4x4_3.jpg',
      },
    ],
  },
];

/cars/index.js

import { cars } from '../../data';
import Link from 'next/link';

export default function Categories({ car }) {
  return (
    {car.map((c) => (
      <Link key={c.id} href={`/cars/${c.name}`} passHref>
        <div>{c.name}</div>
      </Link>
    ))}
  );
}

export const getStaticProps = async () => {
  return {
    props: {
      car: cars,
    },
  };
}; 

/cars/[name].js

import React from 'react';

import { cars } from '../../data';

export default function CategoriesCars({ cars }) {
  return (
    <div>
      {cars.models.map((m) => (
        <p key={m.id}>{m.name}</p>
      ))}
    </div>
  );
}

export const getStaticPaths = async () => {
  const paths = await cars.map((c) => ({
    params: {
      name: c.name,
    },
  }));
  return { paths, fallback: false };
};

export const getStaticProps = async (context) => {
  const { params } = context;
  const response = await cars.filter((c) => c.name === params.name);
  return {
    props: {
      cars: response[0],
    },
  };
};

Upvotes: 3

Views: 3285

Answers (1)

Faruk
Faruk

Reputation: 444

The page folder must be:

pages/
 cars/
  [category]/
   [id]/
    index.jsx
   index.jsx

then go /cars/sedan/2 you can access to category and id variables like this:

cars/[category]/[id]/index.jsx

import React from 'react';
import { useRouter } from 'next/router';

export default function Index() {
  const router = useRouter();
  // router.query.category -> sedan
  // router.query.id -> 2
  return <div>{JSON.stringify(router.query)}</div>;
}

// or 
export const getServerSideProps = async (context) => {
  const { params } = context;
  console.log(params); // { category: 'sedan', id: '2' }
  return {
    props: {
      cars: {},
    },
  };
};

// or if you wish use getStaticProps for SSG (with getStaticPaths)
export const getStaticPaths = async (context) => {
  const paths = cars
    .map((car) =>
      car.models.map((model) => ({
        params: {
          id: model.id.toString(),
          category: car.name,
        },
      }))
    )
    .flat(); // this is important

  return { paths, fallback: false };
};

export const getStaticProps = async (context) => {
  const { params } = context;
  console.log(params);
  return {
    props: {
      cars: {},
    },
  };
};

Example: StackBlitz

Upvotes: 5

Related Questions