File Input 다루는 법

File Input에 대해 자세히 알아보자.

File Input 다루는 법

React에서 <input type="file" />는 다른 폼 요소들에 비해 조금 더 복잡할 수 있습니다. 이 글에서는 파일 입력을 효과적으로 처리하고, 상태 관리 및 유효성 검사를 구현하는 방법을 단계별로 설명하겠습니다.

1. React에서 Form 관리의 어려움

React에서는 Form 데이터를 관리하는 것이 다소 복잡할 수 있습니다. 특히 파일 입력과 같은 경우는 일반적인 Form 요소들과 다른 방법으로 처리해야 하기 때문에 조금 더 신경 써야 합니다.

  • Input 값 상태 관리: 폼의 각 입력 요소마다 값을 추적하고 업데이트하는 것은 번거롭습니다.
  • 유효성 검사: 각 입력마다 별도의 유효성 검사를 구현해야 합니다.

React Hook Form의 도움

  • React Hook Form을 사용하면 폼 입력 값을 효율적으로 관리할 수 있지만, 파일 입력은 다른 입력 요소와는 다르게 특별히 다루어야 합니다.

2. File Input의 특수성

<input type="file" />은 다음과 같은 이유로 일반적인 폼 요소들과 다르게 처리해야 합니다

  • 비제어 컴포넌트: React에서는 <input type="file" />의 값을 프로그래밍적으로 설정할 수 없으며, 오직 사용자가 직접 파일을 선택해야만 값이 설정됩니다. 이 때문에 파일 입력은 비제어 컴포넌트로 사용됩니다.
  • 파일 취소 및 FileList 관리: 파일 선택을 취소하거나, 여러 파일을 관리하는 FileList 객체를 처리하려면 애플리케이션 레벨에서 직접 제어해야 합니다.

File 유효성 검사

파일 입력에도 유효성 검사를 추가하고 싶다면 input 태그에 accept 속성을 사용해 허용할 파일 형식을 지정할 수 있습니다.

<input type='file' accept='.png,.jpg,.jpeg' />

3. File Input의 비제어 컴포넌트 처리

React에서 공식적으로 파일 입력을 다룰 때는 ref를 사용해 파일 선택을 처리합니다. 다음은 React의 공식 문서에서 제시하는 예시입니다.

import React, { useRef } from 'react';
 
const FileInput = () => {
  const fileInputRef = useRef(null);
 
  const handleSubmit = (event) => {
    event.preventDefault();
    if (fileInputRef.current?.files.length > 0) {
      alert(`선택된 파일: ${fileInputRef.current.files[0].name}`);
    } else {
      alert('파일이 선택되지 않았습니다.');
    }
  };
 
  return (
    <form onSubmit={handleSubmit}>
      <label>
        파일 업로드:
        <input type='file' ref={fileInputRef} />
      </label>
      <br />
      <button type='submit'>제출</button>
    </form>
  );
};
 
export default FileInput;

4. React Hook Form을 사용한 파일 입력 처리

React Hook Form을 사용하면 상태 관리가 훨씬 간편해집니다. 하지만 파일 입력은 별도로 다뤄야 하므로, watch와 같은 기능을 활용해 상태 변화를 추적할 수 있습니다.

// Upload.tsx
 
const Upload = () => {
  const { register, handleSubmit, setValue, watch } = useForm<FeedToUpload>();
  const watchThumbnailImage = watch('thumbnailImage');
 
  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <FileInput
        fileName={watchThumbnailImage?.name}
        onChange={(event) =>
          setValue('thumbnailImage', event.currentTarget.files[0])
        }
      />
      <button type='submit'>제출</button>
    </form>
  );
};
 
// FileInput.tsx
 
const FileInput = ({ fileName, ...props }) => {
  return (
    <div>
      <label>
        <input type='file' {...props} />
        <span>파일 선택</span>
      </label>
      <p>{fileName || '파일을 선택해주세요.'}</p>
    </div>
  );
};

핵심 기능 설명

  • watch: watch("thumbnailImage")는 thumbnailImage 필드의 상태를 관찰하여 파일이 선택될 때마다 값이 업데이트됩니다.
  • setValue: 파일 선택 시 setValue를 사용해 thumbnailImage 필드 값을 설정합니다.

5. 정리 및 요약

  • 비제어 컴포넌트로 파일 입력 다루기: 파일 입력은 React에서 비제어 컴포넌트로 다루어야 하며, ref를 사용해 파일에 접근할 수 있습니다.
  • React Hook Form 사용: 파일 입력의 상태를 관리할 때 watchsetValue를 사용하면 쉽게 추적하고 값을 설정할 수 있습니다.
  • 상태 변화 감지: 파일 입력의 상태 변화는 수동으로 관리해야 하며, 이를 위해 FileList와 같은 파일 관리 객체를 직접 다루어야 합니다.