skip to Main Content

I’m new in Next and Typescript and can’t solve the issue, I have tried all possible options that found in the internet and thinking maybe the problem is that the answers were old and something have changed….

I’m getting this error in my restaurant website project while trying to make a categories filter for menu .
I was supposed to get categories from menu. I use Set to get unique categories from menu data and then I make an array from object uniqueCategoriesSet
(I just read in the internet that it can solve the issue with "TypeError: uniqueCategories.map is not a function " but it doesnt).
Before this I was just passing unuqieCategoriesSet to CategoriesButtons as a prop and there was the same issue and also another issue in CategoryButtons component: "Parameter ‘uniqueCategoriesSet’ implicitly has an ‘any’ type."

I’m using framework Next and Typescript

I really appressiate any help!

page.tsx:

"use client"
import React, {useEffect} from 'react'
import { menu } from '../data'
import Link from 'next/link'
import Image from 'next/image'
import CategoryButtons from '../components/CategoryButtons'

const MenuPage = () => {
  const uniqueCategoriesSet = new Set<string>();
  menu.forEach(item => {
    uniqueCategoriesSet.add(item.cat);
  });
  const uniqueCategories: string[] = Array.from(uniqueCategoriesSet);
  return (
    <div className='p-4  '>
      <h1 className='text-center'>Menu</h1> 
      <CategoryButtons {...uniqueCategories}/>
      <div className=" flex flex-wrap">
        {menu.map(item=>(
        <div className=' w-full h-[60vh] flex flex-col items-center justify-center border-2 sm:w-1/2 md:w-1/3 lg:w-1/4'>
          <div className='relative h-[60%] w-full '>
            <Image src="/fruit-salad.png" alt="" fill className='object-contain'/>
          </div>
          <div className='p-4'>
            <h1 className='font-bold'>{item.title}</h1>
            <p>Desc</p>
            <span className='font-bold'>Price</span>
          </div>
        </div>
        ))}
      </div>
    </div>
  )
}


export default MenuPage

CategoryButtons.tsx:

import React from 'react'


const CategoryButtons = (uniqueCategories:string[]) => {
    console.log(typeof(uniqueCategories));
  return (
    <div className='flex items-center gap-2 h-12'>
        <button className='bg-green-600 p-1 text-sm text-white rounded-md'>All</button>
           {uniqueCategories.map((item)=>(
            <button className='bg-green-600 p-1 text-sm text-white rounded-md'>
                {item}
            </button>
       ))}
    </div>
    )
}
export default CategoryButtons
my data - menu:
interface Menu  {
        id: number;
        cat: string;
        title: string;
        desc?: string;
        img?: string;
};


export const menu:Menu[] = [
    {
        id: 1,
        cat: "starters",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
    {
        id: 2,
        cat: "starters",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
    {
        id: 3,
        cat: "main",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
    {
        id: 4,
        cat: "main",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
    {
        id: 5,
        cat: "drinks",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
    {
        id: 6,
        cat: "drinks",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
    {
        id: 7,
        cat: "desserts",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
    {
        id: 8,
        cat: "desserts",
        title: "Fruit salad",
        desc: "Strawberry, banana, avocado",
        img: "/fruit-salad.png",     
    },
]

I just want to press buttons (CategoryButtons component) of menu categories (drinks, Main courses etc..) and be able to filter menu (MenuPage page)

I have tried passing a Set uniqueCategoriesSet to a CategoryButtons
Because I thought that the issue is that map function doesnt work with objects i decided to make an array from the unuqueCategoriesSet
I have tried passing an Array uniqueCategories to a CategoryButtons
(and i checked type of uniqueCategories, it is an object…)

I have tried changing the way I pass unuque Categories to CategoryButtons:
<CategoryButtons {...uniqueCategories}/> <CategoryButtons <CategoryButtons uniqueCategories={uniqueCategories}/>

I have tried to change parameters in CategoryButtons conponent:
const CategoryButtons = (uniqueCategoriesSet) const CategoryButtons = (uniqueCategoriesSet:[string])

3

Answers


  1. Hi I come from Vue rather then React, but the spread on the component looks odd.

    <CategoryButtons {…uniqueCategories} />: In this line, you are spreading the uniqueCategories array into the CategoryButtons component. However, you should pass an array as a prop, not spread its values. To pass an array as a prop, you should do it like this:

    <CategoryButtons categories={uniqueCategories} />.
    

    In the CategoryButtons component, make sure it handles the categories prop correctly. You can then map over the categories array to render buttons.

    Login or Signup to reply.
  2. You should send the props like:

    <CategoryButtons uniqueCat={uniqueCategories}/>
    

    What is sent is a object with property uniqueCat. Read it like:

    const CategoryButtons = (o:object) => {
      const uniqueCategories = o.uniqueCat;
      console.info(Array.isArray(uniqueCategories))
    

    Alternatively destructure it:

    const CategoryButtons = ({uniqueCategories}) => {
      console.info(Array.isArray(uniqueCategories))
    

    Ref: https://react.dev/learn/passing-props-to-a-component

    Login or Signup to reply.
  3. There are couple of things that needs to be corrected in your code. Firstly, the functional component CategoryButtons accepts props which is always of type object. You cannot pass the uniqueCategories array directly. It has to be one of the properties in the props object. Note that it can be named anything. Example below:

    import React from "react";
    
    interface CategoryButtonsProps {
      uniqueCategories: string[];
      otherProps: Int; // other props example
    }
    
    const CategoryButtons = (props: CategoryButtonsProps) => {
      return (
        <div className="flex items-center gap-2 h-12">
          <button className="bg-green-600 p-1 text-sm text-white rounded-md">
            All
          </button>
          {props.uniqueCategories.map((item) => (
            <button
              key={item}
              className="bg-green-600 p-1 text-sm text-white rounded-md"
            >
              {item}
            </button>
          ))}
        </div>
      );
    };
    export default CategoryButtons;
    

    And in the page.tsx file, you would pass the props as shown below:

    <CategoryButtons uniqueCategories={uniqueCategories} />
    

    Hope it helps! here’s a link to the codesandbox where I solved your problem.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search