React 및 Formik을 사용한 파일 업로드 및 유효성 검사

14530 단어
Formik은 파일 업로드를 쉽게 처리하는 방법을 제공하지 않습니다. 다양한 github 문제와 stackoverflow 토론을 보고 적절한 해결책을 찾았습니다.

다음은 파일 크기와 MIME 유형을 확인하는 방법을 보여주는 codesandbox입니다.
링크: https://codesandbox.io/s/hardcore-ully-tdk4iu?file=/src/App.js

Formik에서 파일로 작업하는 기본 아이디어는 파일 입력 구성 요소를 제어하지 않고 ref로 선택한 파일에 액세스하는 것입니다. 추가 정보: https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag

1단계: 양식 내부에 ref를 생성하고 해당 참조를 파일 입력 구성 요소에 전달합니다.

export default function App() {
  const initialValues = {
    files: ""
  };
  const fileRef = useRef(null);
  return (
    <Formik
      initialValues={initialValues}
      validationSchema={Yup.object({
        files: Yup.mixed()
          {/* ... */}
      })}
      onSubmit={(values) => {
        {/* ... */}
      }}
    >
      <Form>
        <FileUpload name="files" fileRef={fileRef} />
        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
}


2단계: <FileUpload> 구성 요소 내부에서 다음과 같이 전달된 ref를 사용합니다.

const FileUpload = ({ fileRef, ...props }) => {
  const [field, meta] = useField(props);
  return (
    <div>
      <label htmlFor="files">Choose files</label>{" "}
      <input ref={fileRef} multiple={true} type="file" {...field} />
      {meta.touched && meta.error ? (
        <div style={{ color: "red" }}>{meta.error}</div>
      ) : null}
    </div>
  );
};


3단계: 업로드된 파일의 크기와 파일의 MIME 유형을 다음과 같이 확인합니다.
참고: ref 를 사용하여 파일에 직접 액세스하고 있습니다.

validationSchema={Yup.object({
        files: Yup.mixed()
          .test("is-file-too-big", "File exceeds 10MB", () => {
            let valid = true;
            const files = fileRef?.current?.files;
            if (files) {
              const fileArr = Array.from(files);
              fileArr.forEach((file) => {
                const size = file.size / 1024 / 1024;
                if (size > 10) {
                  valid = false;
                }
              });
            }
            return valid;
          })
          .test(
            "is-file-of-correct-type",
            "File is not of supported type",
            () => {
              let valid = true;
              const files = fileRef?.current?.files;
              if (files) {
                const fileArr = Array.from(files);
                fileArr.forEach((file) => {
                  const type = file.type.split("/")[1];
                  const validTypes = [
                    "zip",
                    "xml",
                    "xhtml+xml",
                    "plain",
                    "svg+xml",
                    "rtf",
                    "pdf",
                    "jpeg",
                    "png",
                    "jpg",
                    "ogg",
                    "json",
                    "html",
                    "gif",
                    "csv"
                  ];
                  if (!validTypes.includes(type)) {
                    valid = false;
                  }
                });
              }
              return valid;
            }
          )
      })}


참조:
  • https://github.com/jaredpalmer/formik/issues/926
  • https://stackoverflow.com/a/55570763/7358595
  • 좋은 웹페이지 즐겨찾기