Reputation: 303
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.
files: []
as means to mount the images for review before submitting.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.
Upvotes: 5
Views: 57996
Reputation: 109
It is simple You should follow the steps which i wrote and i hope this will help
Upvotes: 0
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
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.
Upvotes: 0
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
Reputation: 77482
TypeError: Cannot read property 'files' of null.
you need to change the state
declaration state = {
files: []
}
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