0

I am well aware that formik does not support file upload. I have read that there are hacks out there. I have tried the one below with onChange, setFieldValue and event.current.target. The problem is that when file is selected, the component renders and the full page goes blank. What am I doing wrong? Thanks!

import React from 'react';
import { Formik, Form, Field } from 'formik';

const initialValues = {
  file: ''
};

const TestArt = () => {
  const onSubmitFile = values => {
    debugger;
  };
  return (
    <div>
      <Formik
        initialValues={initialValues}
        onSubmit={onSubmitFile}
        component={UploadFile}
      />
    </div>
  );
};

function UploadFile({ setFieldValue }) {
  debugger;
  return (
    <div>
      <Form>
        <Field
          id="file"
          type="file"
          name="file"
          onChange={event => {
            setFieldValue('file', event.currentTarget.files[0]);
          }}
        />
        <button>submit</button>
      </Form>
    </div>
  );
}

export default TestArt;

1 Answer 1

4

I am not sure why you think Formik doesn't support files. Formik manages values in state so there is no specific reason you can't use files (or any other type of data) other than that the default Formik field isn't setup to handle these objects.

According to the Formik docs - https://jaredpalmer.com/formik/docs/api/field

will automagically hook up inputs to Formik. It uses the name attribute to match up with Formik state. will default to an HTML element.

What is really key here is how the inputs are hooked up to Formik. In your case you are setting the onChange prop. This will override the default "wiring" of Formik for onChange. Another bit of the default "wiring" of formik is to set the HTML input tag's value equal to the state value for that field. This is where your particular issue is coming from because when using react all file inputs must be uncontrolled (not controlled by state).

According to the react docs - https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag

In React, an is always an uncontrolled component because its value can only be set by a user, and not programmatically.

So to solve this you will want to make a normal HTML input tag with the onChange wired to set the formik value as you desire. The issue with this is as it is uncontrolled it is not in sync with formik. As we already know, we cannot control file inputs so we will have to use a work around. What people typically do is hide their "real" file input component and instead render a "placeholder" component that displays the state. Finally the "placeholder" is wired up using react Ref so that you can interact with the file input without it being rendered from the "placeholder".

import React from "react";
import { Formik, Form } from "formik";

const initialValues = {
  file: ""
};

const TestArt = () => {
  const onSubmitFile = values => {
    debugger;
  };
  return (
    <div>
      <Formik
        initialValues={initialValues}
        onSubmit={onSubmitFile}
        component={UploadFile}
      />
    </div>
  );
};

function UploadFile({ values, setFieldValue }) {
  debugger;
  const fileInput = React.createRef();
  return (
    <div>
      <Form>
        <input
          type="file"
          style={{display: "none"}}
          onChange={event => {
            setFieldValue("file", event.currentTarget.files[0]);
          }}
          ref={fileInput}
        />

        <button type="button" onClick={() => fileInput.current.click()}>
          Choose file
        </button>

        <small>
          {values.file ? values.file.name || "Error" : "No file chosen"}
        </small>

        <br />
        <button>submit</button>
      </Form>
    </div>
  );
}

export default TestArt;

You can also look at this on codesandbox - https://codesandbox.io/s/formik-file-upload-example-39orl

What is also nice now is that you can actually influence how this "placeholder" component looks so you can have fancy input button or whatever (can consider using the file objects other fields such as size - https://developer.mozilla.org/en-US/docs/Web/API/File)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.