back

Posts

input type=file onChange 미작동 문제 해결

2025-08-10

모바일/웹 환경에서 파일 업로드 UI를 커스터마이징하다 보면 다음과 같은 패턴을 자주 사용합니다.

  1. <input type="file">는 숨김 처리
  2. 클릭 가능한 label 또는 div로 파일 선택 제어
  3. 선택된 이미지를 미리보기로 표시
  4. "삭제" 버튼으로 미리보기 제거

이 방식은 UI적으로 깔끔하지만, 특정 상황에서 onChange 이벤트가 동작하지 않는 문제가 발생할 수 있습니다.

1. 문제 상황

아래와 같은 코드에선 이미지를 업로드한 뒤 UI상에서 삭제하고 동일한 파일을 다시 업로드하면 onChange 이벤트가 아예 발생하지 않습니다.

<input
  type="file"
  id="fileInput"
  style={{ display: 'none' }}
  onChange={handleFileChange}
/>

<label htmlFor="fileInput">이미지 선택</label>

{preview && (
  <div>
    <img src={preview} alt="미리보기" />
    <button onClick={handleRemove}>삭제</button>
  </div>
)}

2. 원인

브라우저는 같은 파일을 재선택하면 불필요한 이벤트 호출을 막기 위해 onChange를 발생시키지 않도록 설계되어 있습니다.

즉, UI에서 이미지를 삭제하더라도 input의 files 속성을 초기화하지 않으면 같은 파일은 다시 선택 불가 상태가 됩니다.

이 현상은 플랫폼/브라우저마다 기준은 다르지만 기본적으로 동일한 현상이 발생할 수 있습니다.

플랫폼/브라우저동일 파일 재선택 시 동작비고
안드로이드 Chrome/WebView거의 항상 onChange 미발생문제 가장 자주 발생
iOS Safari메타데이터 변동 시 발생 가능카메라 촬영/갤러리 선택 시 파일이 달라질 수 있음
데스크톱 Chrome/Edge미발생표준 동작
데스크톱 Firefox미발생표준 동작

4. 해결 방법

UI에서 이미지를 삭제할 때 input.value를 초기화해야 합니다.

import { useRef, useState } from "react";

function ImageUploader() {
  const fileInputRef = useRef(null);
  const [preview, setPreview] = useState(null);

  function handleFileChange(e) {
    const file = e.target.files?.[0];
    if (file) {
      const url = URL.createObjectURL(file);
      setPreview(url);
    }
  }

  function handleRemove() {
    setPreview(null);
    if (fileInputRef.current) {
      fileInputRef.current.value = ""; // 핵심: 파일 값 초기화
    }
  }

  return (
    <>
      <input
        type="file"
        ref={fileInputRef}
        style={{ display: "none" }}
        onChange={handleFileChange}
      />
      <label htmlFor="fileInput">이미지 선택</label>

      {preview && (
        <div>
          <img src={preview} alt="미리보기" />
          <button onClick={handleRemove}>삭제</button>
        </div>
      )}
    </>
  );
}

위 코드처럼 새로운 파일을 업로드하기 전, 기존 input을 초기화하면 문제가 해결됩니다.