reactjstypescriptnext.jssanitynext.js13

NEXT JS 13 infinite loop on use State, Error on Params, and error on hook definition


I am trying to create a shopping cart with NEXT JS and I am facing different errors in my code. first thing first I have created a route [product]/[productitems] in my apps folder. in my page.tsx file of [productitems]. I am fetching params to get the product as well as ID of my product. I am using sanity.io for the content of data and used its client.fetch() method to fetch the images.

it is not allowing me to declare my useState below the fetch method so that I can set my default values. If I try to declare them below fetch method I receive 2 errors

TypeError: Cannot destructure property 'params' of 'param' as it is undefined

Invalid hook call. Hooks can only be called inside of the body of a function component

The only way I got rid of this error is by declaring the my state at the top of my component.

But now I am receiving two more errors. I am unable to update states with onClick methods. and my code goes to infinite loop as soon as I click to update quantity or click on any image. what should I do?

  const ProductItem = async ({params}:{params:{
  productitem:string, product:string}}) => {
    const [quantity,setQuantity] = useState(1);
    const [imageURL,setImageUrl] = useState('');

    const response = await client.fetch(`*[_type=="product" && _id =="${params.productitem}" && category->name =="${params.product}"]{
             _id,dressType,image,category->{name},
    }`)

      return <>
      <div className='mt-8 mb-12 flex flex-col lg:flex-row lg:gap-4 justify-center gap-2 mx-4 border-b-4'>
       <div className='flex flex-row lg:flex-col gap-2 justify-center rounded m-4 px-4'>
         {
          response[0].image.map((items:any)=>{
            return <Image src={urlForImage(items).url()} alt="product1" width={100} height={125} className='max-h-[125px] max-w-[100px] object-contain object-top' key={items._key} onClick={(event)=>{
              event.stopPropagation();
              setImageUrl(urlForImage(items).url())
            }}/>
          })
        }
        
       </div>

       <div className='rounded flex justify-center my-4 mx-2'>
          <Image src={imageURL ? imageURL : urlForImage(response[0].image[0]).url()} alt="product main" width={315} height={450}className='max-h-[450px] h-auto max-w-full object-contain object-top'/>
       </div>

       <div className='lg:my-4 lg:mx-2 flex flex-col lg:p-4 mx-auto' >
          <h1 className='text-xl font-semibold'>BRUSHED RAGLAN SWEATSHIRT</h1>
          <h4 className='text-lg font-bold text-gray-500'>Sweater</h4>
          <div className='mt-5 flex flex-col'>
              <h5 className='text-lg font-semibold'>SELECT SIZE</h5>
              <div className='text-lg my-1 space-x-8 py-1'>
                    <span className='rounded border-2 inline font-bold p-2'>XL</span>
                    <span className='rounded border-2 inline font-bold p-2'>L</span>
                    <span className='rounded border-2 inline font-bold p-2'>M</span>
                    <span className='rounded border-2 inline font-bold p-2'>S</span>
              </div>

              <div className='my-4 space-y-2'>
                  <label className='font-bold'>Quantity:</label>
                  <div className='flex flex-row gap-x-2 items-center'>
                        <Button className=' border-2 ' onClick={()=>{
                          if(quantity<=0)return;
                          setQuantity(
                            quantity + 1 
                          )
                        }}>
                          -
                        </Button>
                        <h6 className='text-xl font-bold'>{quantity}</h6>
                        <Button className=' border-2 ' onClick={()=>{

                          setQuantity(quantity + 1)
                          console.log("Quantity",quantity)
                        }}>
                          +
                        </Button>

                        <h4 className='mx-10 text-2xl font-bold'>$ 195.00</h4>
                  </div>

                  <Button className='my-2'>
                      <ShoppingCart className="mr-2 h-4 w-4" /> Add To Cart
                  </Button>
              </div>
          </div>
       </div>
    </div>
    
    <div className='mt-8 flex flex-col flex-wrap sm:max-w-[65%] gap-2 justify-center mx-auto mb-8'>
      <h1 className='text-2xl font-bold px-2'>Product Information</h1>
      <p className=' text-justify text-lg text-gray-500 px-2'>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Expedita earum aspernatur sapiente ut amet quae odit eius totam! Et cupiditate dolores eligendi. Maxime veniam nemo quia eveniet harum mollitia possimus?</p>
    </div>
  </>
    }

I get this infinite loop as soon as I click + or - button or even any of my 3 images where on click is called


Solution

  • Okay I found a solution of my problem, In next JS we got server side components and Client Components. The Problem Lies in the fetch method since this component is client side I cannot call Fetch method to it as this feature is purely of Server components. I have used use Effect hook to call the API that I was calling using fetch method. since it broke infinite loop hell my code began to run properly. comment down if anyone wants the code snippet I will post it for you.