How to handle Image / File upload with Formik using reactjs?
Problem:
You are trying to make a social media website with ReactJs. In This website, you have a page where you want to create a profile page. And, you want to know how to upload an image from your computer and save it to the database also displaying it to the profile. So, In this article, we are going to talk about ReactJS: How to handle Image / File upload with Formik?
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { AcntAction } from '../../actions/user/AccountPg1Action';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
class Info extends Component {
constructor(props) {
super(props)
this.state = {
userData: {
userImg: '',
}
}
}
handleFileUpload = (event) => {
this.setState({userImg: event.currentTarget.files[0]})
};
handleChange = event => {
const {name, value} = event.target
this.setState({
[name]: value
})
}
handleSubmit = event => {
let that = this;
const { AcntAction } = that.props;
event.preventDefault();
let accountDataInputs = {
userImg: that.state.image,
}
that.setState({
userData: accountDataInputs,
})
AcntAction(accountDataInputs)
}
AccountInfoView = () => {
return (
<section id="account_sec" className="second_form">
<div className="container">
<React.Fragment>
<Formik
initialValues={{
file: null,
}}
render={(values) => {
return(
<Form onSubmit={this.handleSubmit}>
<StepOne
handleChange={this.handleChange}
file= {this.state.userImg}
handleFileUpload={this.handleFileUpload}
/>
</Form>
);
}}
/>
</React.Fragment>
)
}
}
function StepOne(props) {
console.log(props.userImg)
if (props.currentStep !== 1) {
return null
}
return(
<div className="upload">
<label htmlFor="profile">
<div>
<img src="example.png" alt="" />
<img src={props.userImg} alt="" />
<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
<span>Add your avatar</span>
)
}
But when you console log event target.file[0] it responds with undefined.
Solution :
You are using Formik to upload files. But formik does not support file upload by default. For this you can do this:
<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. On submit you can the info about the file by using:
onSubmit={(values) => {
console.log({
fileName: values.file.name,
type: values.file.type,
size: `${values.file.size} bytes`
})
}
Now to set the file into components state you can do this:
onChange={(event) => {
this.setState({"file": event.currentTarget.files[0]})};
}}
Now according to your code, you have to handle the file this way:
handleFileUpload = (event) => {
this.setState({"file": event.currentTarget.files[0]})
};
Now pass the function to StepOne component :
<StepOne
handleChange={this.handleChange}
file= {this.state.image}
handleFileUpload={this.handleFileUpload}
/>
In stepOne component where you upload file change input:
<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
And now you need to preview the image to do that you can create a blob and pass it:
<img src={URL.createObjectURL(FILE_OBJECT)} />
Update:
As the URL.createObjectURL method is deprecated you need to use srcObject to do that you can use ref. For Example:
In the constructor you can use:
constructor(props) {
super(props)
this.imageElRef = React.createRef(null)
}
Now handle you have to handle the changed function:
handleFileUpload = (event) => {
let reader = new FileReader();
let file = event.target.files[0];
reader.onloadend = () => {
this.setState({
file: reader.result
});
};
reader.readAsDataURL(file);
}
and pass this to img tag:
<img src={this.state.file} />
If this solution does not solve your problem you can comment below.