Source:  Twitter logo

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.

  • I have created files: [] as means to mount the images for review before submitting.
  • Tried creating an interface files: File[] = file then declaring it in state but get a different error that file does not exist on type {}
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.

  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>
5 users liked answer #0dislike answer #05
Oleksandr T. profile pic
Oleksandr T.

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>
0 users liked answer #1dislike answer #10
Ali Raza profile pic
Ali Raza

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

0 users liked answer #2dislike answer #20
Zekarias Taye Hirpo profile pic
Zekarias Taye Hirpo

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;
0 users liked answer #3dislike answer #30
Abdelrahman Tareq profile pic
Abdelrahman Tareq

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).