Problem:
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])
Solution:
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.