Search code examples
reactjsinputuse-statemultiple-file-upload

Reactjs input multiple files with preview not working on first selection


So I'm trying to make a component to select multiple images and display a preview, so then the user can see the selected images and decide to upload it or not.

So here's my code to select images and display the preview :

  const [fileObj, setFileObj] = useState([]);

const loadImageHandler = (event) => {
    setImageUpload(event.target.files);
    setShowProgress(true);

    for (let i = 0; i < event.target.files.length; i++) {
      setFileObj((arr) => [
        ...arr,
        {
          file: event.target.files[i],
          url: URL.createObjectURL(event.target.files[i]),
        },
      ]);
    }
  };

return (
    <div className={classes.container}>
      <div className={classes.imgPreview}>
        {fileObj.length > 2 &&
          fileObj.map((obj, index) => <img id={index} src={obj.url} />)}
      </div>
      <div>
        <label id="articleImg">Select images for your article :</label>
        <input
          name="articleImg"
          type="file"
          onChange={loadImageHandler}
          accept="image/*"
          required={required}
          multiple
        />
      </div>
    </div>
  );

The problem is that when I select my images, the input field indicates that there are 3 images selected for example, but the preview does not display anything. It is when I select the images a second time that the preview shows the new images that have just been selected and the previous ones. How can I update my preview during the first selection?


Solution

  • That because you are using setState method in the loop. So in next render, actually there is only one data in fileObj array. Because of 'fileObj.length > 2' condition, so the image won't be rendered.

    Try change 'loadImageHandler' method to this way.

    const loadImageHandler = (event) => {
        setImageUpload(event.target.files);
        setShowProgress(true);
        // First to figure out the result array by using map method
        const result = event.target.files.map(v => ({
           file: v,
           url: URL.createObjectURL(v),
        }));
        
        setFileObj((arr) => [...arr, ...result]);
     };