ReactJS: How to handle Image / File upload with Formik? - reactjs

I am designing a profile page for my site using ReactJS.
Now my question is how do I upload the image from local machine and save it to the database and also displaying it in the profile page
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { AccountAction } from '../../actions/user/AccountPg1Action';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
class AccountInfo extends Component {
constructor(props) {
super(props)
this.state = {
currentStep: 1,
userAccountData: {
userid: '',
useravtar: '',
attachement_id: '',
}
}
}
handleFileUpload = (event) => {
this.setState({useravtar: event.currentTarget.files[0]})
};
handleChange = event => {
const {name, value} = event.target
this.setState({
[name]: value
})
}
handleSubmit = event => {
let that = this;
const { AccountAction } = that.props;
event.preventDefault();
let accountInputs = {
userid: 49,
useravtar: that.state.image,
attachement_id: 478,
}
that.setState({
userAccountData: accountInputs,
})
AccountAction(accountInputs)
}
AccountInfoView = () => {
console.log(this.state.useravtar)
return (
<section id="account_sec" className="second_form">
<div className="container">
<React.Fragment>
<Formik
initialValues={‌{
file: null,
email: '',
phone: ''
}}
validationSchema={accountInfoSchema}
render={(values) => {
return(
<Form onSubmit={this.handleSubmit}>
<Step1
currentStep={this.state.currentStep}
handleChange={this.handleChange}
file= {this.state.useravtar}
handleFileUpload={this.handleFileUpload}
/>
</Form>
);
}}
/>
</React.Fragment>
)
}
render() {
return (
<div>{this.authView()}</div>
)
}
}
function Step1(props) {
console.log(props.useravtar)
if (props.currentStep !== 1) {
return null
}
return(
<div className="upload">
<label htmlFor="profile">
<div className="imgbox">
<img src="images/trans_116X116.png" alt="" />
<img src={props.useravtar} className="absoImg" alt="" />
</div>
</label>
<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
<span className="guide_leb">Add your avatar</span>
</div>
)
}
When I do console in handleChange action for event.target.file[0] it responds with undefined.
Also, doing a console.log(this.state.useravtar) in handleSubmit action it shows a pathname like c:/fakepath/imgname.jpg
P.S: I have a multiple forms so I am using it in a Step wise. And i am using Redux Reducer for storing the data.
I have referred this link but my requirement is not looking like this.

Formik doesnot support fileupload by default, But you can try the following
<input id="file" name="file" type="file" onChange={(event) => {
setFieldValue("file", event.currentTarget.files[0]);
}} />
Here "file" represents the key that you are using for holding the file
And on submit you can get the filename, size etc for the file by using
onSubmit={(values) => {
console.log({
fileName: values.file.name,
type: values.file.type,
size: `${values.file.size} bytes`
})
If you want to set the file into components state then you can use
onChange={(event) => {
this.setState({"file": event.currentTarget.files[0]})};
}}
According to your code, you have to handle file upload as below
In AccountInfo add a function to handle file upload
handleFileUpload = (event) => {
this.setState({WAHTEVETKEYYOUNEED: event.currentTarget.files[0]})};
}
And pass the same function to Step1 Component as below
<Step1
currentStep={this.state.currentStep}
handleChange={this.handleChange}
file= {this.state.image}
handleFileUpload={this.handleFileUpload}
/>
In Step1 Component where you upload the file, Change the input as
<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
If you need to preview the uploaded image then you can create a blob and pass the same as source for image as below
<img src={URL.createObjectURL(FILE_OBJECT)} />
EDIT-1
As URL.createObjectURL method is deprecated due to security issues, we need to use srcObject for Media Elements, to use that you can use ref to assign srcObject, for example
Assuming you are using class Components,
Constructor
in constructor you can use
constructor(props) {
super(props)
this.imageElRef = React.createRef(null)
}
HANDLE CHANGE FUNCTION
handleFileUpload = (event) => {
let reader = new FileReader();
let file = event.target.files[0];
reader.onloadend = () => {
this.setState({
file: reader.result
});
};
reader.readAsDataURL(file);
}
Element
<img src={this.state.file} />

Here is how I resolved it with Formik and Material UI
in your JS file, just declare a variable avatarPreview like below
const [avatarPreview, setAvatarPreview] = useState('/avatars/default.png');
<Box
display='flex'
textAlign='center'
justifyContent='center'
flexDirection='column'>
<ImageAvatar size='md' src={avatarPreview || user?.avatar} />
<Button
variant='contained'
component='label'
startIcon={<CloudUploadIcon />}>
Choose Avatar
<input
name='avatar'
accept='image/*'
id='contained-button-file'
type='file'
hidden
onChange={(e) => {
const fileReader = new FileReader();
fileReader.onload = () => {
if (fileReader.readyState === 2) {
setFieldValue('avatar', fileReader.result);
setAvatarPreview(fileReader.result);
}
};
fileReader.readAsDataURL(e.target.files[0]);
}}
/>
</Button>
</Box>
Default Preview:
After choosing avatar:

You can upload single or multiple files with validation using Formik as follows:
import "./App.css";
import { useEffect, useState } from "react";
import * as Yup from "yup";
import { Formik, Field, Form, ErrorMessage, useField } from "formik";
import axios from "axios";
function App() {
return (
<Formik
initialValues={{
profile: [],
}}
validationSchema={Yup.object({
profile:Yup.array().min(1,"select at least 1 file")
})}
onSubmit={(values, props) => {
let data = new FormData();
values.profile.forEach((photo, index) => {
data.append(`photo${index}`, values.profile[index]);
});
axios
.post("you_api_for_file_upload", data, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((response) => {
console.log(response);
})
.catch((err) => {
console.log(err);
});
}}
>
{(formik) => {
return (
<>
<Form>
<input
id="file"
name="profile"
type="file"
onChange={(event) => {
const files = event.target.files;
let myFiles =Array.from(files);
formik.setFieldValue("profile", myFiles);
}}
multiple
/>
<ErrorMessage name="profile"/>
<button type="submit" disabled={formik.isSubmitting}>
Submit
</button>
</Form>
</>
);
}}
</Formik>
);
}
export default App;
Note: you can customize min(your choice, "your message") as per your need.
validationSchema={Yup.object({
profile:Yup.array().min(1,"select at least 1 file")
})}

FormIk does not support file uploading and we need to do it in custom way.
Just trigger onChange event and set the file.
If you face any error of setFieldValue in TypeScript, then you simply do this:
onChange={(event) => {
if (event.currentTarget.files) {
formik.setFieldValue(
"file",
event.currentTarget.files[0]
);
}

To handle file in formik with backend all you need to do add the input given below (you can change avatar to anything you want):
<input
type="file"
name="avatar"
onChange={(event) => {
setFieldValue('avatar', event.currentTarget.files[0]);
}}
/>
onSubmit you can access file using values obj like values.avatar.
On server-side (express) to access the file we use req.file
You also have to use multer that will automatically detect file to handle it on the server-side

To handle file in formik with backend all you need to do add the input given below (you can change avatar to anything you want):
<input
type="file"
name="avatar"
onChange={(event) => {
setFieldValue('avatar', event.currentTarget.files[0]);
}}
/>
onSubmit you can access file using values obj like values.avatar.
On server-side (express) to access the file we use req.file You also have to use multer & cloudinary that will detect file to handle it on the server-side

I used simple trick
<Field name="image">
{ (form , meta , value ) =>
const {setFieldValue} = form
return (
<input name="image" type="file" onChange={(e) => setFieldValue(e.target.file[0])}
)
}
</Field>
for multiple image
<input name="image" type="file" onChange={(e) => setFieldValue(e.target.files)}
or use loop
for( i=0 ; i < e.target.file; i++){
setFieldValue([...image , e.target.file])
}

Related

How do I join the file url field (Firestore storage) with the other fields in Firestore? (react)

I've trying to:
Upload image to firebase storage
create field 'fileUrl' in Firestore under the 'articles' document
reference the doc in Firestore so that each image knows to which article it is assigned.
I managed to do all of that in a way but the issue is that when I submit the form with a title, content and image, it creates a new document in Firestore with just a the image ('fileUrl'), instead of creating a document that includes the rest of the form's data.
I know that this is probably because in my UploadFile.js I'm creating a new document but how do I join the Field created in UploadFile.js with the fields in AddArticle.js?
I'm also getting ''Unhandled Rejection (TypeError): Cannot read property 'state' of undefined' for this line:
firebase.firestore().collection('articles').doc(this.state.documentId).update({
fileUrl: fileUrl
})
UploadFile.js
import React from "react";
import firebase from '../Firebase';
function UploadFile() {
const [fileUrl, setFileUrl] = React.useState(null);
const onFileChange = async (e) => {
const file = e.target.files[0]
const storageRef = firebase.storage().ref()
const fileRef = storageRef.child(file.name)
await fileRef.put(file);
setFileUrl(await fileRef.getDownloadURL().then(fileUrl => {
firebase.firestore().collection('articles').doc(this.state.documentId).update({
fileUrl: fileUrl
})
.then(() => {
setFileUrl('')
})
} ));
};
return (
<>
<input type="file" onChange={onFileChange} />
<div>
<img width="100" height="100" src={fileUrl} alt=''/>
</div>
</>
);
}
export default UploadFile;
AddArticle.js
import React, { Component } from 'react';
import firebase from '../Firebase';
import UploadFile from '../components/UploadFile';
class AddArticle extends Component {
constructor() {
super();
this.ref = firebase.firestore().collection('articles');
this.state = {
title: '',
content: '',
fileUrl: ''
};
}
onChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value;
this.setState(state);
}
onSubmit = (e) => {
e.preventDefault();
const { title, content, fileUrl } = this.state;
this.ref.add({
title,
content,
fileUrl
}).then((docRef) => {
this.setState({
title: '',
content: '',
fileUrl: '',
documentId: docRef.id
});
this.props.history.push("/")
})
.catch((error) => {
console.error("Error adding document: ", error);
});
}
render() {
const { title, content, fileUrl } = this.state;
return (
<div className="container">
<br></br><br></br><br></br>
<div className="panel panel-default">
<div className="panel-heading">
<h3 className="panel-title text-center">
Create a new article
</h3>
</div>
<br></br><br></br>
<div className="panel-body">
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label for="title">Title:</label>
<input type="text" className="form-control" name="title" value={title} onChange={this.onChange} placeholder="Title" />
</div>
<div className="form-group">
<label for="content">Content:</label>
<textArea className="form-control" name="content" onChange={this.onChange} placeholder="Content" cols="80" rows="20">{content}</textArea>
</div>
{/* <input type="file" onChange={this.onFileChange} /> */}
<UploadFile onChange={this.onChange} value={fileUrl}/>
<button type="submit" className="btn btn-success">Submit</button>
</form>
</div>
</div>
</div>
);
}
}
export default AddArticle;
Each time you call firebase.firestore().collection('articles').add(...), you add a new document to the database. Since you call that in both AddArticle and in UploadFile, your image URL and the other fields indeed will end up in separate documents.
The way you're handling the file upload is a bit unusual to me, as I'd normally expect that upload to happen when the other fields are also submitted. Right now, it's not clear to me what the image belong to, as J.A.Hernández also commented.
Either way: you'll need to remove one of the firebase.firestore().collection('articles').add(...) calls and instead pass the document ID into that call. Say that you first add the text fields and then upload the image, the UploadFile can then update the document with:
firebase.firestore().collection('articles').doc(documentId).update({
fileUrl: fileUrl
})
One way to pass the document ID from the to is by keeping it in the state:
this.ref.add({
title,
content,
fileUrl
}).then((docRef) => {
this.setState({
title: '',
content: '',
fileUrl: '',
documentId: docRef.id
});
this.props.history.push("/")
})
And then:
firebase.firestore().collection('articles').doc(this.state.documentId).update({
fileUrl: fileUrl
})

How to create a add image input in formik

I want to create a customized input field in formik for an image upload. I want to pass binary file data to backend, but it is taking the file location. Can you help me?
Here is the boilerplate code:
import React from 'react';
import { useField } from 'formik';
import { Form, Col, Row } from 'react-bootstrap';
const FileInput = ({ label, ...props }) => {
const [field, meta] = useField(props);
return (
<>
<Form.Group as={Row} controlId="">
<Form.Label htmlFor={props.id || props.name} column sm={3}>
{label}
</Form.Label>
{props.initalImage ? (
<img height="35px" alt={props.initalImage} src={props.initalImage} />
) : null}
<Col sm={4}>
<Form.Control
{...field}
{...props}
accept={props.accept}
isValid={meta.touched && !meta.error}
isInvalid={Boolean(meta.touched && meta.error)}
/>
{meta.error ? (
<>
<Form.Control.Feedback type="invalid">
{meta.error}
</Form.Control.Feedback>
</>
) : null}
<span className="form-text text-muted mt-3">
Please choose an icon which is min. 256x256px.
</span>
</Col>
</Form.Group>
</>
);
};
export { FileInput };
and here is where I am calling it:
<FileInput
label="Light Icon:"
type="file"
name="lightIcon"
accept="image/x-png"
onBlur
/>
I tried this but it is not working:
<FileInput
label="Light Icon:"
type="file"
name="lightIcon"
accept="image/x-png"
onBlur
onChange={(e) => {
setFieldValue('lightIcon', e.target.files[0]);
}}
/>
The trick with <input> elements with type="file" is that we shouldn't set their value manually, it actually uses it's own mechanism along with browser's security implementations and set it itself on the client's machine.
So we don't have access to the real path of the file on the disk, instead we are able to use a FileReader object to asynchronously read contents of the file as blob of buffer and pass it to our parent component.
There are cases where you can change file input's value
programmatically, like to null to reset your input.
The following example implements an UploadFiled component with type="file" get wrapped with a custom Field component, whenever child component getting update, a file is being uploaded, and parent component will knows and starts reading the contents of the specified Blob, once finished, the result attribute contains a data url representing the file's data will set as it's value. It currently accepts an image base on the validation that is set for it using Yup.
The traditional application/json type won’t help in uploading the image to your server, the FormData will. You need to write your handleSubmit() using the form data and pass the values handled by Formik.
Check my CodeSandbox for the working demo.
const handleSubmit= () => {
// Create an object of formData
const formData = new FormData();
// Update the formData object
formData.append("myFile", file, file.name);
// Details of the uploaded file
console.log(file);
// Request made to the backend api
// Send formData object
axios.post("api/uploadfile", formData);
};
// UploadForm.jsx
import React, { useState, useEffect } from "react";
import { Field, useField } from "formik";
import { Grid, FormHelperText } from "#material-ui/core";
import UploadField from "../../FormFields/UploadField";
import Thumb from "../Helper/Thumb";
const ImageForm = (props) => {
const {
formField: { image }
} = props;
const [field, meta, helper] = useField(image.name);
const { touched, error } = meta;
const { setValue } = helper;
const isError = touched && error && true;
const { value } = field;
const [fileName, setFileName] = useState(value.name);
const [file, setFile] = useState(value.file);
const [src, setSrc] = useState(value.src);
const _onChange = (e) => {
let reader = new FileReader();
let file = e.target.files[0];
if (file) {
reader.onloadend = () => setFileName(file.name);
if (file.name !== fileName) {
reader.readAsDataURL(file);
setSrc(reader);
setFile(file);
}
}
};
useEffect(() => {
if (file && fileName && src) {
setValue({ file: file, src: src, name: fileName });
console.log(fileName);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [src, fileName, file]);
return (
<React.Fragment>
<Grid container spacing={3} justify="center" alignItems="center">
<Grid item xs={12}>
<label>
{image.label}
</label>
<br />
<div
style={{
display: "flex",
justifyContent: "flex-start",
fontSize: "1.2em"
}}
>
<Field
variant="outlined"
field={field}
component={UploadField}
onChange={_onChange}
isError={isError}
/>
{isError && <FormHelperText color={"red"}>{error}</FormHelperText>}
</div>
</Grid>
<Grid item>{file && src && <Thumb file={file} src={src}></Thumb>}</Grid>
</Grid>
</React.Fragment>
);
};
export default ImageForm;
import React from "react";
import { Field } from "formik";
const UploadField = ({
field,
form: { touched, errors },
name,
label,
isError,
...props
}) => {
return (
<>
<Field
variant="outlined"
name="uploader"
title={label}
type={"file"}
{...props}
/>
</>
);
};
export default UploadField;

Cannot update state with file uploader in reactJS

I created a simple image uploader component that is rendered in a new-image-form that extends a form. but when handling a change(an image upload), the state is updated with an empty opbject (and not with the file object). I tried to debug it but anything goes right until this.setState. Can anyone helps?
NewImagesForm :
class NewImagesForm extends Form {
state = {
data: {
_id: 0,
name: "",
file: null,
},
errors: {},
apiEndpoint: "",
};
render() {
return (
<div className="new-menu-item-form">
<form onSubmit={this.handleSubmit}>
{this.renderInput("name", "Name")}
{this.renderUploadFile("file", "Upload")}
{this.renderButton("Add")}
</form>
</div>
);
}
Form
class Form extends Component {
state = { data: {}, errors: {} };
handleFileUpload = (e) => {
const data = { ...this.state.data };
data[e.currentTarget.name] = e.target.files[0];
this.setState({ data });
};
renderUploadFile(name, label) {
const { data } = this.state;
return (
<UploadImage
name={name}
label={label}
value={data[name]}
onChange={this.handleFileUpload}
></UploadImage>
);
}
}
export default Form;
File Upload Component
const UploadImage = ({ name, label, error, onChange }) => {
return (
<div className="input-group">
<div className="custom-file">
<input
type="file"
onChange={onChange}
className="custom-file-input"
id={name}
name={name}
></input>
{label && (
<label className="custom-file-label" htmlFor={name}>
{label}
</label>
)}
</div>
<div className="input-group-append">
<button className="btn btn-outline-secondary" type="button">
Button
</button>
</div>
</div>
);
};
export default UploadImage;
First of all, react does not recommend the use of extends, because of the combination of extends.
In the Form component, the setState() trigger the render() , but there is no render(). setState does not allow renderUploadFile to be re-executed.
It would be a good idea to use the UploadImage component in the NewImagesForm component. Don't let NewImagesForm extends Form.
But the exactly same way works for me with custom input text and custom select boxes, see the differences:
handleChange = (e) => {
const data = { ...this.state.data };
data[e.currentTarget.name] = e.currentTarget.value;
this.setState({ data });
};
handleFileUpload = (e) => {
const data = { ...this.state.data };
data[e.currentTarget.name] = e.target.files[0];
this.setState({ data });
};

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.
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.
In order to fix the error TypeError: Cannot read property 'files' of null. you need to change the state declaration
state = {
files: []
}
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>
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;
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>
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
It is simple You should follow the steps which i wrote and i hope this will help

How to upload an image in React JS?

<div className="mb-1">
Image <span className="font-css top">*</span>
<div className="">
<input type="file" id="file-input" name="ImageStyle"/>
</div>
</div>
This is the snippet i provided that i was using to pick the file from the device in react js,
Using this i can select the file and that filename is also shown as well
What i want is now to store this file on S3 or anywhere and get its URL from there and POST it to my server using fetch api call.
import React, { useState } from "react";
const UploadAndDisplayImage = () => {
const [selectedImage, setSelectedImage] = useState(null);
return (
<div>
<h1>Upload and Display Image usign React Hook's</h1>
{selectedImage && (
<div>
<img
alt="not found"
width={"250px"}
src={URL.createObjectURL(selectedImage)}
/>
<br />
<button onClick={() => setSelectedImage(null)}>Remove</button>
</div>
)}
<br />
<br />
<input
type="file"
name="myImage"
onChange={(event) => {
console.log(event.target.files[0]);
setSelectedImage(event.target.files[0]);
}}
/>
</div>
);
};
export default UploadAndDisplayImage;
Upload the image from your file and display it on your page in react,
you can also get the image object in the state when we select the image
to display on the webpage you have to convert the image object to object using URL.createObjectURL(fileObject)
import React, { Component } from "react";
class DisplayImage extends Component {
constructor(props) {
super(props);
this.state = {
image: null
};
// if we are using arrow function binding is not required
// this.onImageChange = this.onImageChange.bind(this);
}
onImageChange = event => {
if (event.target.files && event.target.files[0]) {
let img = event.target.files[0];
this.setState({
image: URL.createObjectURL(img)
});
}
};
render() {
return (
<div>
<div>
<div>
<img src={this.state.image} />
<h1>Select Image</h1>
<input type="file" name="myImage" onChange={this.onImageChange} />
</div>
</div>
</div>
);
}
}
export default DisplayImage;
If you want to upload image and post it to an API. Then you install react-image-uploader. It saves the image to your local port and also in your database by raising a POST request.
This code let you upload image to the server,the backend code is written in nestjs,and display the image which will be uploaded.I have used the formdata.
import React, { useEffect, useState } from "react";
function Product() {
const { REACT_APP_REST } = process.env;
const [file, setFile] = useState([]);
const handleFile = event => {
setFile(
URL.createObjectURL(event.target.files[0])
);
const formData = new FormData();
formData.append("fileupload", event.target.files[0]);
fetch(REACT_APP_REST + "/product/upload", {
method: 'POST',
body: formData,
dataType: "jsonp"
})
};
return (
<>
<Container fluid>
<Col md="4">
<Card className="card-user">
<img src={file} />
<Card.Body>
<Form.Group>
<label>IMAGE</label>
<Form.Control
type="file"
required="required"
onChange={handleFile}
></Form.Control>
</Form.Group>
</Card.Body>
<hr></hr>
</Card>
</Col>
</Container>
</>
);
}
export default Product;
using react-uploady you can do this very easily:
import React from "react";
import Uploady from "#rpldy/uploady";
import UploadButton from "#rpldy/upload-button";
import UploadPreview from "#rpldy/upload-preview";
const filterBySize = (file) => {
//filter out images larger than 5MB
return file.size <= 5242880;
};
const App = () => (
<Uploady
destination={{ url: "my-server.com/upload" }}
fileFilter={filterBySize}
accept="image/*"
>
<UploadButton />
<UploadPreview />
</Uploady>
);
Failed to execute 'createObjectURL' on 'URL': Overload resolution failed.
For some reason I coudn't use URL.createObjectURL(image) as
const [image, setImage] = useState(null);
const [imgURL, setImgURL] = useState();
<img src={URL.createObjectURL(image)}/>
So I save the Url in the state for instant display on the button click method. This worked!
setImgURL(URL.createObjectURL(image));
Unfortunately, I was still getting the same error when I use useEffect.
useEffect(() => {
setImgURL(URL.createObjectURL(image));
}, [image]);

Resources