Dharmik soni
Dharmik soni

Reputation: 363

Trying to add multiple images in react , but it only displays one image

I am trying to select multiple images, and the images are being selected and stored in the state, but only one image is displayed.Below is the code for the same

//Selecting the image and displaying the image

 <div className="md-form mb-5">
          <input type="file" id="form29" name='images' onChange={e => pickImage(e)} className="form-control validate" multiple hidden/>
          <button className="btn btn-outline-dark btn-sm" onClick={e => selectImage(e)}>Pick Image</button>
        </div>
                <div className="row text-center">
                    {image.length > 0 ?
                    image.map(img => (
                        <div className="col-md-4" key={img.url}>
                            <img src={img.url} alt={img.name} className="img-fluid"/>
                            <span style={{cursor: 'pointer'}}>
                            <i class="far fa-trash-alt" onClick={e => deleteImage(img.name, e)}></i>
                            </span>
                        </div>
                    )) : <p>No Images Picked</p>}
                </div>

//Defining the state

const [addDiary, setAddDiary] = useState({date: null, content: null, images: []});
const [ image, setImage ] = useState([]);

//Defining the methods to store and delete image

const selectImage = (e) => {
        document.getElementById('form29').click();
    }

    const deleteImage = (name, e) => {
        const remainingImage = image.filter(img => {return img.name !== name});
        setImage(remainingImage);
        const remainingImageState = addDiary.images.filter(img => 
            {
            return img.name !== name});
        setAddDiary({...addDiary, images: remainingImageState });
    }

    const pickImage = (e) => {
       console.log(e, 'e obj')
        for(const file of e.target.files) {
            const reader = new FileReader();
            reader.onload = (e) => {

               setImage([...image, {url: URL.createObjectURL(file), name: file.name}]);
               console.log(e.target.name)
               setAddDiary({ ...addDiary, images: [...addDiary.images, file]});
              };
               reader.readAsDataURL(file);
            }

        }

Upvotes: 1

Views: 1438

Answers (2)

Juorder Gonzalez
Juorder Gonzalez

Reputation: 1652

The issue here is that you are updating the image each time is loaded, so you should first load all images into cache an finally update the state, you can do by putting this code

const pickImage = (e) => {
  console.log(e, 'e obj');
  const limitImages = e.target.files.length;
  let count = 0;
  const images = [];
  for(const file of e.target.files) {
    const reader = new FileReader();
    reader.onload = (e) => {
      images.push({ url: URL.createObjectURL(file), name: file.name });
      count++;

      if (count === limitImages) {
        // here all images are loaded, so update the state
        setImage(images);
        setAddDiary({ ...addDiary, images: addDiary.images.concat(images)});
      }      
    };
    reader.readAsDataURL(file);
  }
}

Remember you should handle the error event too, too notify the user that was an error

So you can avoid the selectImage method to trigger onClick event into the input, just by adding an id to your input file and use a label to trigger the event, like this:

<div className="md-form mb-5">
  <input type="file" id="form29" name='images' onChange={e => pickImage(e)} className="form-control validate" multiple hidden id="file-picker" />
  <button className="btn btn-outline-dark btn-sm" onClick={e => selectImage(e)}>
    <label id={'file-picker'}>
      Pick Image
    </label>
  </button>
</div>

I hope it can help you

Upvotes: 1

ageoff
ageoff

Reputation: 2828

Your key for you map is set as an object. Try setting as the image name to avoid ommitting. React cannot tell the keys apart if they are objects:

<div className="col-md-4" key={img.name}>
  <img src={img} alt={img} className="img-fluid"/>
  <span style={{cursor: 'pointer'}}>
  <i class="far fa-trash-alt" onClick={e => deleteImage(img.name, e)}></i>
  </span>
</div>

Upvotes: 0

Related Questions