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

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


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:Default avatar upload

After choosing avatar:After you choose your 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")      })}