Reputation: 186
I've edited the original post as it had two separate problems and ultimately AKX in the comments helped me solve what the real problem was.
I'm trying to do an image preview for multiple images using appendChild as shown in the MDN docs, but when I go to submit the form and want to reset the page I'm noticing that using appendChild can be kind of an anti-pattern in React. I want to come up with a solution where I store an array of image tags that I could then just set to empty on submit to clear the page, as opposed to having to query select them all with document and remove.
With the code below I'm only rendering the first image out of a batch upload of multiple files. Single image uploads one after another work fine.
const previewMainImages = (e) => {
const files = Object.values(e.currentTarget.files)
if (mainImageFiles.length + 1 > 10) {
setErr(errMessage = 'Only 10 images can be uploaded here')
return
}
function readAndPreview(file) {
var reader = new FileReader();
reader.onloadend = () => {
var image = <img src={reader.result} alt={file.name}/>
setMain(mainImageFiles = [...mainImageFiles, file])
setMainImages(mainImages.concat(image))
}
reader.readAsDataURL(file);
}
if (files) {
files.forEach((f, i) => {
console.log(f)
readAndPreview(f)
});
}
}
Upvotes: 0
Views: 1452
Reputation: 186
I'm still learning javascript and React so I forgot about useRef
. Also based on AKX's advice I also changed from storing image html tags to storing image data objects that I then map over to display the image tags in the form.
There seemed to be a problem where I was using two setState's and this was preventing the .forEach
loop from iterating over all imgObjs.
So at the top of my file I define my useRef:
let mainImages = useRef([]);
I tried to remove both setStates within reader.onloadend
but I found that the second setState for storing image files was actually needed to cause a re-render to ultimately display the images.
const previewMainImages = (e) => {
const files = Object.values(e.currentTarget.files)
if (mainImageFiles.length + 1 > 10) {
setErr(errMessage = 'Only 10 images can be uploaded here')
return
}
const readAndPreview = (file) => {
var reader = new FileReader();
reader.onloadend = () => {
var imgObj = {};
imgObj.src = reader.result
imgObj.alt = file.name
mainImages.current.push(imgObj)
setMain(mainImageFiles = [...mainImageFiles, file])
}
reader.readAsDataURL(file);
}
if (files) {
files.forEach((f, i) => {
readAndPreview(f)
});
}
}
And then in the relevant part of the html I'm simply doing this:
<div
className={'mainPreview'}
>
<h2>Main Images</h2>
<p>{errMessage}</p>
<input
type='file'
multiple
name='image'
accept='.png, .jpg, jpeg'
onChange={e => previewMainImages(e)}
/>
{mainImages.current.map((img, i) => {
return <img key={i} src={img.src} alt={img.alt} />
})}
</div>
And then my reset inputs work like this:
const resetInputs = () => {
setMain(mainImageFiles = []);
setBody(bodyImageFiles = []);
mainImages.current = [];
setDescription(description = '');
setTag(tag = '');
setTags(tags = []);
setErr(errMessage = '');
}
I'm still having a problem with the file input values not being reset but I'm going to leave that for another day.
Upvotes: 1