Can't upload file with useField in formik

Viewed 454

I am trying to upload files with formik. I have the following code.

import { Field, ErrorMessage, useField, FieldProps } from "formik";
import { InputHTMLAttributes } from "react";

type FormikImageFieldProps = InputHTMLAttributes<HTMLElement> & {
  label: string;
  name: string;
  component?: string;
};

const FormikImageField: React.FC<FormikImageFieldProps> = ({
  label,
  size: _,
  ...props
}) => {
  const [field, { error, touched }, helper] = useField<FieldProps>(props);

  return (
    <div className="mb-6 pt-3 rounded bg-gray-200">
      <label
        className="block text-gray-700 text-sm font-bold mb-2 ml-3"
        htmlFor={field.name}
      >
        {label}
      </label>
      <Field
        {...field}
        {...props}
        type="file"
        onChange={(e: any) => {
          helper.setValue(e.currentTarget.files[0]);
        }}
        id={field.name}
        className={`bg-gray-200 rounded w-full text-gray-700 focus:outline-none border-b-4 border-gray-300 focus:border-purple-600 transition duration-500 px-3 pb-3 ${
          touched && error ? "border-red-600" : ""
        }`}
      />
      {touched && (
        <ErrorMessage name={field.name}>
          {() => <div className="text-md text-red-600 italic">{error}</div>}
        </ErrorMessage>
      )}
    </div>
  );
};

export default FormikImageField;

Now I the problem here is my helper.setValue function is not setting the value of the field. I am getting this error.

Unhandled Runtime Error
InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': 
This input element accepts a filename, which may only be programmatically set to the empty string.

Any Idea what's causing this error. Also, I want to follow this code and I don't want to use setFormikField because that was causing another error. Thanks for your time.

1 Answers

I faced today exactly same problem. I was struggling with it for a while. I figured out that you have to pass whole files object. It's of type FilesList, which is only readable object, which stores Files objects. It should be:

helper.setValue(e.currentTarget.files);

or

helper.setValue([ e.currentTarget.files[0] ]);

What is also important, in your Formik form you can set field type to File[], which makes it easy to set initial value as empty array - []. This approach gives you also a lot of flexibility in your customisations. Before calling setValue method you can compare files coming in an event and those currently stored by Formik in field object (from useForm).

Related