skip to Main Content

I’m using the App router of nextjs 13, with typescript, and I’m trying to create dynamic pages and generate the paths for them with generateStaticParams().

The function generateStaticParams() seems to work, and it collects the correct information. But when I want to use the information in my component, I get a undefined value.

The page is fetchting the data correctly if I hardcode the ID, so I only need to swap this for the ID collected with the generateStaticParams.

How can I make sure that the page is receiving the data from generateStaticParams?

/src/app/coffeeplaces/[coffeeplace]/page.tsx
import fetchCoffeePlace from "@/api/fetchCoffeeplace";
import { db } from "@/helpers/firebaseConfig";
import { collection, getDocs } from "firebase/firestore";
import Image from "next/image";
import { Suspense } from "react";
import ImagesCarousel from "./components/imagesCarousel";
import Link from "next/link";
import CoffeeMainDetails from "./components/coffeeMainDetails";

export default async function Page({ params }: { params: { id: string, slug: string } }) {
  const { id, slug } = params

  // this comes back UNDEFINED
  console.log('id', params.id) // or id
  console.log('slug', params.slug) // or slug

  // This hardcoded option works to fetch the data
  // const id = 'r7CFv3t4Ni5sNl20wE8h'

  const CoffeeplaceData = fetchCoffeePlace(id);
  const CoffeeplaceInfoData = fetchCoffeePlace(id); // 

  const coffeeplace = await CoffeeplaceData;

  return (
    <div>
      <Link href={'/coffeeplaces'} className="text-sm font-light">Back to listing</Link>
      <Suspense fallback={<div>Loading...</div>}>
        <CoffeeplaceInfo promise={CoffeeplaceInfoData} />
      </Suspense>
    </div>
  );
}

async function CoffeeplaceInfo({ promise, }: { promise: Promise<CoffeePlace>; }) {
  const coffeeplaceInfo = await promise;
  return (
      <>
      <div className="pt-6 lg:flex w-full">
        <ImagesCarousel featuredImage={coffeeplaceInfo.featuredImage} />
        <CoffeeMainDetails name={coffeeplaceInfo.name} priceRange={coffeeplaceInfo.priceRange} organic={coffeeplaceInfo.organic} fairTrade={coffeeplaceInfo.fairTrade}/>
      </div>
      </>
    )
}

export async function generateStaticParams() { // tried with this: generateStaticParams({ params: { id, slug }}: any)
  const coffeePlaces = await getDocs(collection(db, "coffeePlaces"));
  const data = coffeePlaces.docs.map((doc) => ({
    id: doc.id,
    ...doc.data()
  }));

  var slugify = require('slugify')

  const result = data.map((item) => {
    const slug = slugify(item.name, {
      replacement: '-',  
      lower: true,  
      strict: true,
    });

    // these are logging the correct values
    console.log(item.id);
    console.log(slug);
    
    return {
      params: {
        id: item.id,
        slug: slug
      }
    };
  }); 

  // this is logging the correct result
  // [{ params: { id: '9ZVOCYsngTksBKXqQQOH', slug: 'coffeeplace-1' } }, { params: { id: 'r7CFv3t4Ni5sNl20wE8h', slug: 'example-2' } } ]

  return result; 
}

Using parallel Data Fetching

Small other thing, might be related, in the generateStaticParams function, when I loop over the result, for the item.name it says: Property 'name' does not exist on type '{ id: string; }')

2

Answers


  1. Bart.
    I am glad to answer your question.
    In my humble opinion, there’s some errors to fix.
    This is my code snippets that corrected yours.

    First part.

    export default async function Page({ params }: { params: { id: string, slug: 
    string } }) {
        const { id, slug } = params;    // this was commented.
    
        // ...
    }
    

    Second part.

    export async function generateStaticParams() {
      // ...
    
      const result = data.map((item) => {
        const slug = slugify(item.name, {
          replacement: '-',
          lower: true,
          strict: true,
        });
    
        return {
          params: {                  // you should return object with 'params' key
            id: item.id,
            slug: slug
          }
        };
      });
    
      return result;
    }
    

    I wonder this would be okay but please try it once.

    Login or Signup to reply.
  2. your result array has this format

    result=[params: {id: "id_1",slug: "slug_1"},params: {id: "id_2",slug: "slug_2"},.....]
    

    when you reach params in Page component, you should be using,

    const { id, slug } = params.params
    

    because params in each dynamic page is

     params=params: {id: "id_1",slug: "slug_1"}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search