开发者问题收集

使用 Formik 和 React 正确处理多个文件输入

2021-04-06
7199

我找不到使用 Formik 和 React 处理多个文件输入的正确方法。

import { Formik, Field } from "formik";

const MyForm = () => {
  const handleOnSubmit = (actions) => {
    actions.setFieldValue("files", "");
  };

  return (
    <Formik initialValues={{ files: "" }} onSubmit={handleOnSubmit}>
      {({ values, handleSubmit }) => (
        <form onSubmit={handleSubmit}>
          <Field
            id="files"
            name="files"
            type="file"
            multiple
            value={values.files}
            onChange={(event) => {
              setFieldValue("files", Array.from(event.target.files));
            }}
          />
          <button type="submit">Submit</button>
        </form>
      )}
    </Formik>
  );
};

如果传递 value={values.files ,则会收到 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.

如果传递 value={values.files ? undefined : ""> ,则可以工作,但会收到 React 警告:

A component is changing an uncontrolled input to be controlled.

如果传递 value={undefined> ,则无法控制输入值(用于在提交表单时清空文件选择)。

并且如果传递 value="" ,则在输入中选择文件时无法获得所选文件的名称(或所选文件的数量)。

我遗漏了什么吗?谢谢。

查看 Codesandbox.io 上的示例。

2个回答

您可以使用 useRef 来获取对文件输入的引用并像这样清除它。

import { Formik, Field } from "formik";
import { useRef } from "react";

export default function App() {
  const fileRef = useRef();

  return (
    <div className="App">
      <Formik
        initialValues={{ files: null }}
        onSubmit={console.log}
      >
        {({ setFieldValue, handleSubmit }) => (
          <form onSubmit={handleSubmit}>
            <Field
              innerRef={fileRef}
              name="files"
              type="file"
              multiple
            />
            <button type="submit">Submit</button>
          </form>
        )}
      </Formik>
      <button onClick={() => (fileRef.current.value = null)}>Clear</button>
    </div>
  );
}

Sathish
2021-04-08

我通过将 files 设置为 event.currentTarget.files 并使用 <input/> 代替 Formik 的 <Field/> ,使您的示例正常运行。

import { Formik } from "formik";

export default function App() {
  return (
    <div className="App">
      <Formik
        initialValues={{ files: null }}
        onSubmit={(values) => {
          console.log(values);
        }}
      >
        {({ setFieldValue, handleSubmit }) => (
          <form onSubmit={handleSubmit}>
            <input
              name="files"
              type="file"
              multiple
              onChange={(event) => {
                setFieldValue("files", event.currentTarget.files);
              }}
            />
            <button type="submit">Submit</button>
          </form>
        )}
      </Formik>
    </div>
  );
}

您可以在此处 查看沙盒

tdranv
2021-04-06