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.
- 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>
}
</>
)
}