UseState doesn't work, it renders the previews photo of the product

WEBSITE GIF

Hello,

I am making ecommerce website using react.js and django DRF.. here is the issues..

1.

as you can see the gif, I tried to implement the function that changes the representative picture

when I click on the small images using useState.. However, when I refresh the page,

the representative picture disappears.

  1. when I click the other product, it shows the previews product that I clicked..

Here's my definition of the driving principle.

In two actions, call the data from api and store it in each variable.

use useState() to render the representative Picture, and when I click other images,

useState is going to change the src url of the image.. and having trouble..

I know it is messy and long codes.. please help me.. thank you!

django codes are here

models.py

class Product(models.Model):

name = models.CharField(max_length=255, blank=False)
category = models.ManyToManyField(ProductCategory)
thumbnail_image = models.ImageField(null=True, blank=True)
discription = models.TextField(null=False, blank=False)
price = models.DecimalField(max_digits=20, decimal_places=2, null=False, blank=False)
stock = models.IntegerField(default=0)
tag = models.CharField(max_length=255, null=True, blank=True)
date = models.DateTimeField(auto_now=True)
enable = models.BooleanField(default=True)

    def image_tag(self):
        if self.thumbnail_image:
            return mark_safe('<img src="%s" style="width: 45px; height:45px;" />' % 
            self.thumbnail_image.url)
        else:
            return 'No Image Found'
            image_tag.short_description = 'Image'

   def __str__(self):
       return self.name

class ProductImages(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True, blank=True)
    images = models.ImageField(null=True, blank=True)

    def __str__(self):
        return str(self.images)

views.py

@api_view(['GET'])
def ProductImage(request,pk):
    if request.method == 'GET':
        images = ProductImages.objects.filter(product=pk)
        serializer = ProductImagesSerializer(images, many=True)
        return Response(serializer.data)

ProductDetailReducer

import {
PRODUCT_REQUEST,
PRODUCT_SUCCESS,
PRODUCT_FAIL,

PRODUCT_IMAGES_REQUEST,
PRODUCT_IMAGES_SUCCESS,
PRODUCT_IMAGES_FAIL
} from '../constants/ProductConstants'

export const ProductDetailReducer = ( state ={ product:[] }, action ) =>{
  switch( action.type){
    case PRODUCT_REQUEST:
        return { loading: true, product: [] }
    
    case PRODUCT_SUCCESS:
        return { loading: false, product: action.payload }
    
    case PRODUCT_FAIL:
        return { loading: false, error: action.payload }

    default:
        return state
    }
    

}


export const ProductDetaiImagesReducer = ( state ={ images:[] }, action ) =>{

switch( action.type){
    case PRODUCT_IMAGES_REQUEST:
        return { loading: true, images: [] }
    
    case PRODUCT_IMAGES_SUCCESS:
        return { loading: false, images: action.payload }
    
    case PRODUCT_IMAGES_FAIL:
        return { loading: false, images: action.error }

    default:
        return state
    }
    

}

productDetailAction

import axios from 'axios'
import {
PRODUCT_REQUEST,
PRODUCT_SUCCESS,
PRODUCT_FAIL,

PRODUCT_IMAGES_REQUEST,
PRODUCT_IMAGES_SUCCESS,
PRODUCT_IMAGES_FAIL
} from '../constants/ProductConstants'


export const ProductDetails = (id)=>async (dispatch) =>{

try{
    dispatch({type:PRODUCT_REQUEST})
    const { data } = await axios.get(`http://127.0.0.1:8000/api/product/${id}`)
    
    dispatch({
        type:PRODUCT_SUCCESS,
        payload: data
    })
}

catch{
    dispatch({
        type:PRODUCT_FAIL,
        error: 'Unable to retrieve the product.'
    })
}

}

export const ProductImagesDetails = (id)=>async (dispatch) =>{

try{
    dispatch({type:PRODUCT_IMAGES_REQUEST})
    const images = await axios.get(`http://127.0.0.1:8000/api/product_images/${id}`)
    dispatch({
        type:PRODUCT_IMAGES_SUCCESS,
        payload: images.data
    })
}

catch{
    dispatch({
        type:PRODUCT_IMAGES_FAIL,
        error: 'Unable to retrieve the product.'
    })
}

}

productDetail.js

import { useEffect, useState } from "react"
import { useDispatch, useSelector } from "react-redux"
import { useParams, useNavigate  } from "react-router-dom"
import { ProductDetails } from '../action/ProductDetailAction'
import { ProductImagesDetails } from "../action/ProductDetailAction"
import { addToCart } from "../action/CartAction"
export default function ProductDetail(){

const history = useNavigate()
const dispatch =  useDispatch()
const {id} = useParams()
const { loading, product, error } = useSelector(state=> state.productDetail)
const { images } = useSelector(state=> state.productImages)
const productImage = product.thumbnail_image
const [qty, setQty] = useState(1)
const [img, setImg] = useState(productImage)
console.log(productImage)

useEffect(()=>{ 
    
    dispatch(ProductDetails(id))
    dispatch(ProductImagesDetails(id))
    
},[dispatch,id])

const addToCartHanddler = ()=>{

    if (window.confirm('move to the cart?')){
        history(`/cart/${id}?qty=${qty}`)
    } else {
            dispatch(addToCart(id,qty))
    }

    
    
}
const CehckoutHanddler = ()=>{
    history(`/cart/${id}?qty=${qty}`)
}

return (
    <>
    { loading ? <h1 style={{ textAlign:'center', marginTop:'100px'}}>loading...</h1>
        : error ? <h1>error</h1> 
        : <div style={{display:'flex', justifyContent:'center', flexWrap:'wrap', marginTop:'30px'}}>
        <div>
        <img style={{width:'500px',height:'500px'}} src={`http://127.0.0.1:8000${img}`} alt='product.name' />
        <div style={{display:'flex', justifyContent:'center', flexWrap:'wrap', marginTop:'30px'}}>
        {images && images.map(x=> (<div key={x.id} style={{width:'120px',height:'120px',marginLeft:'10px',border:'1px solid #dcdcdc'}}>
        <img onClick={()=>setImg(x.images)} style={{height:'100%',width:'100%',objectFit:'cover'}} src={`http://127.0.0.1:8000${x.images}`} alt='product.name' />
        </div>
        ))}
        </div>
        </div>
        <div style={{marginLeft:'40px', border:'1px solid #dcdcdc' ,width:'330px', padding:'40px'}}> 
        <h1>{product.name}</h1>
        <p>{product.discription}</p>
        <div>
            {product.stock > 0 ? (<select onChange={(e)=>setQty(e.target.value)}  style={{width:'200px',borderRadius:'0px',padding:'10px',border:'1px solid #dcdcdc'}}>
                {[...Array(product.stock).keys()].map(x=>(
                    <option key={x+1} value={x+1}>{x+1}</option>
                ))}
            </select>): [] }
            { <p>{product.stock} in stock.</p> }
            <p style={{color:'#a1a1a1',fontSize:'0.7rem'}}>*the select options shows the current stock of the item</p>
            
        </div>
        <h2 style={{marginTop:'100px'}}>Total: ${(product.price * qty).toFixed(2)}</h2>
        
        <button onClick={CehckoutHanddler} disabled={product.stock === 0} style={{width:'150px',height:'40px',backgroundColor:'black',color:'white',margin:'30px 3px', border:'2px solid #000'}}>{product.stock >0 ? 'CheckOut' : 'Out of Stock'}</button>
        <button onClick={addToCartHanddler} disabled={product.stock === 0} style={{width:'150px',height:'40px',backgroundColor:'white',margin:'30px 3px', border:'2px solid #000'}}>{product.stock >0 ? 'Add to Cart' : 'Out of Stock'}</button>
        </div>
    </div>
    }
      
    </>
    
)

}

Back to Top