I’m working on a React component that allows users to edit a product and upload images. While I’m able to set and preview a single image correctly, I’m having trouble with previewing multiple images. Specifically, the images do not display as expected right after the upload. in the line 78 the console.log do log the array of base 64 images but i don’t know why it do not previewing it
Here’s my code snippet:
"use client"
import { usePathname } from 'next/navigation'
import React, { useState } from 'react'
import { useEffect } from 'react'
import axios from 'axios'
import { OrbitProgress } from 'react-loading-indicators'
import Image from 'next/image'
import { render } from 'react-dom'
const EditContent = () => {
// Get Data //
const path = usePathname();
const pathQeury = path.split("/");
const id = pathQeury[3];
const [fetched,setFetched] = useState(false);
const [products,setProducts] = useState([])
useEffect(() => {
axios.get(`/api/OneProductGet/${id}`)
.then((response) =>
{setProducts(response.data);
setFetched(true);
})
.catch((error) => console.error(error))
},[id])
console.log(products)
//-------------------------------------------//
// Data //
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [price, setPrice] = useState(0);
const [singleImage, setSingleImage] = useState(null);
const [multipleImages, setMultipleImages] = useState([]);
const [SingleImageSrc, setSingleImageSrc] = useState();
const [MultipleImageSrc, setMultipleImageSrc] = useState([]);
let MultipleImagesSrc = [];
let MultipleImages = [];
//------------------------------------------------------//
// Tranforme Single Image Data To src //
useEffect(() => {
if(singleImage){
const render = new FileReader();
render.onload = (e) => {
setSingleImageSrc(e.target.result);
}
render.readAsDataURL(singleImage);
}
else{
setSingleImageSrc(products[0]?.images[0]);
}
},[singleImage,products[0]])
console.log(SingleImageSrc)
//-------------------------------------//
// Function Of Handling Multiple Images //
MultipleImages.push(...multipleImages);
useEffect(() => {
if(MultipleImages){
MultipleImages.map((image) => {
const render = new FileReader();
render.onload = (e) => {
setMultipleImageSrc(e.target.result);
}
render.readAsDataURL(image);
MultipleImagesSrc.push(MultipleImageSrc);
})
}
console.log(MultipleImagesSrc)
},[MultipleImages])
//--------------------------------------//
// Function Of Handling Data //
async function handleSubmit(){
const formData = new FormData();
formData.append('title', title);
formData.append('description', description);
formData.append('price', price);
formData.append('singleImage', singleImage);
formData.append('multipleImages', multipleImages);
}
if (!fetched){
return(
<div className='flex justify-center items-center bg-white w-full m-5 rounded-lg ml-0 p-5'>
<OrbitProgress color="#1e3a8a" size="medium" text="" textColor="" />
</div>
);
}
return (
<div className=' bg-white w-full m-5 rounded-lg ml-0 p-5'>
<h1 className=' ml-2 text-3xl mb-4 font-semibold text-blue-900'>Edit Product</h1>
<form className='flex flex-col gap-1' onSubmit={handleSubmit}>
<label className='ml-1 text-blue-900 '>
Product name <span className='text-red-500'>*</span>
</label>
<input required={true} className='mb-2 border p-1 rounded-lg' type="text" name="title" placeholder={products[0]?.name}/>
<label className='ml-1 text-blue-900 '>
Description
</label>
<textarea className='mb-2 border p-1 rounded-lg' name="content" rows="4" cols="50" placeholder={products[0]?.description} />
<label className='ml-1 text-blue-900 '>Price (in MAD) <span className='text-red-500'>*</span></label>
<input required={true} className='mb-2 border p-1 rounded-lg' type="number" name="price" placeholder={products[0]?.price} />
<label className='text-blue-900'>Main Product Image <span className='text-red-500'>*</span></label>
<div className='grid grid-cols-4 gap-3'>
{ SingleImageSrc? (
<div className='relative group h-full w-full flex rounded-xl overflow-hidden border-2'>
<img
src={SingleImageSrc}
alt='hello'
></img>
<div className='group-hover:opacity-20 transition-all bg-black h-full absolute opacity-0 w-full'></div>
<button className=' absolute right-0' onClick={() => {setSingleImageSrc(undefined)}}>
<i class='bx bx-x text-red-500 invisible group-hover:visible absolute m-2 text-[30px] right-0'></i>
</button>
</div>
) : (<div className='hidden'></div>
)}
<div className='flex flex-col justify-center items-center text-center py-14 px-5 overflow-hidden relative border-dashed border-2 rounded-lg h-full '>
<i class='bx bx-cloud-upload text-blue-900 text-[3em]'></i>
<p className='w-[80%] '><span className='opacity-60'>Drop your images here or select</span> <span className='text-blue-900 opacity-100'>click to browse</span></p>
<input required={true} type="file" name="singleImage" accept="image/*" className='z-10 w-full h-full absolute opacity-0' onChange={(e) => {setSingleImage(e.target.files[0])}}/>
</div>
</div>
<label className='text-blue-900'>Product Images <span className='text-red-500'>*</span></label>
<div className='grid grid-cols-4'>
{ MultipleImagesSrc.length > 0 ? (
MultipleImagesSrc.map((image, i) => (
<div key={i} className='relative group h-[232px] w-full rounded-xl overflow-hidden border-2'>
<img
src={image} // Properly setting the base64 string here
className='w-full h-full absolute'
alt={`image-${i}`} // Giving a unique alt attribute
/>
<div className='group-hover:opacity-20 transition-all bg-black h-full absolute opacity-0 w-full'></div>
<button className='absolute right-0' onClick={() => {MultipleImagesSrc.splice(i, 1)}}>
<i className='bx bx-x text-red-500 invisible group-hover:visible absolute m-2 text-[30px] right-0'></i>
</button>
</div>
))
) : (
<div className='hidden'></div>
)}
<div className='flex flex-col justify-center items-center text-center py-14 px-5 overflow-hidden relative border h-fit '>
<i class='bx bx-cloud-upload text-blue-900 text-[3em]'></i>
<p className='w-[80%] '><span className='opacity-60'>Drop your images here or select</span> <span className='text-blue-900 opacity-100'>click to browse</span></p>
<input required={true} type="file" name="singleImage" accept="image/*" className='z-10 w-full h-full absolute opacity-0' multiple onChange={(e) => {setMultipleImages(e.target.files)}}/>
</div>
</div>
<input type="submit" value="save" className='bg-blue-900 w-fit text-white pb-1 px-3 rounded-lg ' />
</form>
</div>
)
}
export default EditContent
i tried to map the MultipleImagesSrc after i checked that it contain the base 64 of the images but it did not preview it
The problem:
The multiple images do not display as expected right after they are uploaded. I suspect it may be related to how I’m handling the state updates for the image previews.
The current method of rendering MultipleImagesSrc may not be working correctly.
Environment:
Next.js
React
Using Tailwind CSS for styling