我正在尝试使用 next js 和 typescript 构建一个电子商务网站,但我在使用产品的虚拟数据数组时遇到问题

问题描述 投票:0回答:1
"use client"
import Container from "@/components/Container";
import ProductDetails from "./ProductDetails";
import ListRating from "./ListRating";
import { products } from "@/utils/products";

interface IParams {
  productId?: string;
}

const Product = ({ params }: { params: IParams }) => {
  console.log('params:', params);

  const product = products.find((item) => item.id === params.productId);

  if (!product) {
    // Handle product not found case
    return <div>Product not found</div>;
  }

  return (
    <div className="p-8">
      <Container>
        <ProductDetails product={product} />
      </Container>
    </div>
  );
};

export default Product;

所以这是旨在帮助我获取产品数据的代码,但这是我不断收到的错误

⨯ TypeError: Cannot read properties of undefined (reading 'id')
    at ProductDetails (./app/products/[productid]/ProductDetails.tsx:31:21)
  34 | 
  35 |     const [CartProduct,setcartProduct]= useState<CartProductType>({
> 36 |         id: product.id,
     |                    ^
  37 |         name: product.name,
  38 |         description: product.id,
  39 |         category:product.category,

然后我决定添加 if 条件,现在我看到的是当我单击该项目时未找到产品

"use client"

import Button from "@/components/products/Button";
import ProductImages from "@/components/products/productImages";
import SetColor from "@/components/products/setColour";
import SetQuantity from "@/components/products/setQuantity";
import { UseCart } from "@/hook/useCart";
import { Rating } from "@mui/material";
import { useRouter } from "next/navigation";
import { useCallback, useState, useEffect } from "react";
import {BsFillCheckCircleFill} from 'react-icons/bs';

interface ProductDetailsProps{
    product:any
}

export type CartProductType= {
    id:string,
    name:string,
    description:string,
    category:string,
    brand:string,
    selectedImg:SelectedImgType,
    quantity:number,
    price:number
}

export type SelectedImgType={
    color:string,
    colorCode:string,
    image: string
}
const ProductDetails:React.FC<ProductDetailsProps> = ({product}) => {

   

    const [CartProduct,setcartProduct]= useState<CartProductType>({
        id: product.id,
        name: product.name,
        description: product.id,
        category:product.category,
        brand:product.brand,
        selectedImg:{...product.images[0]},
        quantity: 1,
        price:product.price
    });

    const {handleAddProductCart,cartProducts} = UseCart();
    const [isProductinCart,setIsProductinCart]= useState(false);
    const router= useRouter();
    
    const Horizontal = ()=>{
        return (<hr className=" w-1/2 my-2"/>)
    }

   
    const{cartTotalQty}= UseCart()
    
   

    
    useEffect(() => {
        console.log(CartProduct);
    }, [CartProduct]);
    
    console.log(cartProducts)
    useEffect(()=>{
        setIsProductinCart(false)
        if (cartProducts) {
            const existingIndex= cartProducts.findIndex((item)=>item.id ===product.id)

            if (existingIndex > -1){
                setIsProductinCart(true)
            }
        } 
    },[cartProducts])
    const ProductRating = product.reviews.reduce((acc:number,item:any)=>item.rating + acc,0) / product.reviews.length


    const handleColorSelect=useCallback((value:SelectedImgType)=>{
        setcartProduct((prev)=>{
            return {...prev,selectedImg:value}
        })
    },[CartProduct.selectedImg])


   
    const handleQuantityInc= useCallback(()=>{
        setcartProduct((prev)=>{

            if (prev.quantity<99){
                return{...prev, quantity: prev.quantity + 1}
            }
            return prev;
        })
    },[CartProduct])

    const handleQuantityDec = useCallback(() => {
    setcartProduct((prev) => {

        if (prev.quantity > 1) {
            return { ...prev, quantity: prev.quantity - 1 };
        }
        
        return prev;
        
    });
}, [CartProduct]);



    return ( 
        <div className="grid grid-cols-1 md:grid-cols-2 gap-12">
            <ProductImages product={product} cartProduct={CartProduct} handleColourSelect={handleColorSelect}/>
            <div className="flex flex-col gap-1"><h2 className="text-2xl">{product.name}</h2>
            <div className="flex gap-2">
            <Rating value={ProductRating} readOnly/>
            <div className="flex gap-2">{product.reviews.length} rewiews</div>
            </div>
            <Horizontal/>
            <div className=" text-justify">{product.description}</div>
            <Horizontal/>
            <div>
                <span className="font-semibold">Category: </span>{product.category}
                
            </div>
            <div>
            <span className="font-semibold">Brand: </span>{product.brand}
            </div>
            <div className={product.inStock ?' text-teal-400':' text-red-400'}>{product.inStock ?'In Stock':'Out of Stock'}</div>
            <Horizontal/>
            {isProductinCart?
            <>
            <p className="mb-2 text-slate-500 flex items-center gap-2">
            <BsFillCheckCircleFill size={20} className="text-teal-400" />
            <span>Product added to Cart</span>
            </p>
            <div className=" max-w-[300px]">
                <Button label="View Cart" outline onClick={()=>{router.push('/cart')}}/>
            </div>
            </>:
            <>
              <SetColor cartProduct={CartProduct} images={product.images} handleColorSelect={handleColorSelect}/>
            <Horizontal/>
            <SetQuantity cartProduct={CartProduct} handleQuantityDec={handleQuantityDec} handleQuantityInc={handleQuantityInc} />
            <Horizontal/>
            <div className=" max-w-[300px]">
                <Button  label="Add to cart" onClick={()=>handleAddProductCart(CartProduct)}/>
                </div>
            </>}
            
            </div>
            
        </div>
     );
}
 
export default ProductDetails;

这是产品详细信息页面,当我点击产品卡时会显示 https://github.com/briankaine1604/bloomy.git 链接到包含代码(如果需要)的 github 存储库

reactjs typescript next.js e-commerce
1个回答
0
投票

您遇到的问题是由于产品 ID 及其接口 IParams 的动态路由的命名约定存在错误。您将产品 ID 的文件夹命名为 productid,并带有小写“i”,但在界面 IParams 中,您传递的是带有大写“I”的 productId。您需要对文件夹及其接口 IParams 使用相同的命名约定。您可以使用 productidproductId

© www.soinside.com 2019 - 2024. All rights reserved.