Prozak
Prozak

Reputation: 303

Uploading multiple images with React

I would like to upload multiple images first by previewing them then submitting to send them off. I have encountered this: TypeError: Cannot read property 'files' of null. It also only lets me upload just one image.

import * as React from "react"

class ImageUpload extends React.Component {
  state: {
    files: []
  }

  fileSelectedHandler = (file: any) => {
    let addedFiles = this.state.files.concat(file)
    this.setState({ files: addedFiles })
    console.log("upload file " + file.name)
  }

  render() {
    return (
      < form >
        <div>
          <h2>Upload images</h2>
        </div>
        <h3>Images</h3>
        <input type="file" onChange={this.fileSelectedHandler} />
      </form>
    )
  }
}

export default ImageUpload

I expect it to allow me to select multiple images and store them in the array before sending them off as a batch. Is this even the right way to do it? Any feedback is greatly appreciated.

Upvotes: 5

Views: 57996

Answers (5)

Elgun  Ezmemmedov
Elgun Ezmemmedov

Reputation: 109

create states(the images state u can use in api if you wanna send those images to api

handle images with createProductImageChange

add input with multiple attribute and use imagesPreviewState for whoweing on the screen

It is simple You should follow the steps which i wrote and i hope this will help

Upvotes: 0

Abdelrahman Tareq
Abdelrahman Tareq

Reputation: 2297

Updated Answer with Typescript as a sperate componnent

import React, { useState, useEffect } from "react";

const UploadAndDisplayImage = () => {
  const [images, setImages] = useState([] as any);
  const [imageURLS, setImageURLs] = useState([]);
  useEffect(() => {
    if (images.length < 1) return;
    const newImageUrls: any = [];
    images.forEach((image:any) => newImageUrls.push(URL.createObjectURL(image)));
    setImageURLs(newImageUrls);
  }, [images]);

  function onImageChange(e: any) {
    setImages([...e.target.files]);
  }

  return (
    <>
      <input type="file" multiple accept="image/*" onChange={onImageChange} />
      {imageURLS.map((imageSrc) => (
        <img src={imageSrc} alt="not fount" width={"250px"} />
      ))}
    </>
  );
};

export default UploadAndDisplayImage;

Upvotes: 3

Zekarias Taye Hirpo
Zekarias Taye Hirpo

Reputation: 847

You can solve this problem by multiple input fields. You are able to track the input field used to upload the file using their unique "ID". Please take a look to the code that I shared.

Input field

onChange handler

file handler based on id

Upvotes: 0

Ali Raza
Ali Raza

Reputation: 1

Handle Form Initial data:

const initialProducts = {
name: "",   
featured_image: "", //for single image
slider_images: [], // (array of strings)   
};

useState

const [products, setProducts] = useState(initialProducts);

Function: Handle Input Fields

const handleInput = (e) => {
let updateValues = { ...products };
updateValues[e.target.name] = e.target.value;
setProducts(updateValues);
console.log("Update input values", updateValues);
};

Function: Handle Multiple Images

 const handleSliderImages = (e) => {
  if (e.target.files) {
  setProducts({ ...products, slider_images: [...e.target.files] });
  }
  console.log("Update slider images", products);
};

FormGroup for Input Fields

<FormGroup className="my-3">
  <Label for="name">Name</Label>
   <Field
    name="name"
    id="name"
    onChange={handleInput}
    value={products.name}
   />
</FormGroup>

FormGroup for single Image

 <FormGroup className="my-3">
  <Label for="featured_image">Featured Image</Label>
  <CustomInput
   type="file"
   id="featured_image"
   name="featured_image"
   onChange={handleInput}
   value={products.featured_image}                  
  />               
 </FormGroup>

FormGroup for Multiple Images

<FormGroup className="my-3">
 <Label for="slider_images">Slider Images</Label>
 <CustomInput
 multiple
 type="file"
 id="slider_images"
 name="slider_images"
 onChange={handleSliderImages}
 />                
</FormGroup>

Upvotes: 0

Oleksandr T.
Oleksandr T.

Reputation: 77482

  1. In order to fix the error TypeError: Cannot read property 'files' of null. you need to change the state declaration
state = {
   files: []
}
  1. If you want to have the opportunity to select multiple files you can use multiple option
<input type="file" multiple onChange={this.fileSelectedHandler} />

Or if you want to select image one by one, your implementation should work, just fix the state declaration and use e.target.files to get selected file

class ImageUpload extends React.Component {
  state = {
    files: []
  }

  fileSelectedHandler = (e) => {
    this.setState({ files: [...this.state.files, ...e.target.files] })
  }

  render() {
    return (
      <form>
        <div><h2>Upload images</h2></div>
        <h3>Images</h3>
        <input type="file" multiple onChange={this.fileSelectedHandler} />
      </form>
    )
  }
}


ReactDOM.render(<ImageUpload />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Upvotes: 8

Related Questions