React/React 문법

[React]동일한 파일 업로드 구현

DevStory 2022. 7. 27.

React에서 동일한 파일 업로드 구현

React에서 파일 업로드 구현하는 방법은 아래 포스팅에서 소개했으나 회사 프로젝트에서 파일 업로드를 구현하는 과정에서 한 가지 문제가 발생했습니다.

 

이번 포스팅에서 설명하는 소스 코드가 이해되지 않는다면 아래 포스팅을 꼭 읽어주세요.

 

[React]파일 업로드 구현

파일 업로드 버튼을 외부 라이브러리에서 제공하는 버튼 컴포넌트를 사용하고 싶은데 해당 라이브러리에서 파일 업로드 기능을 지원하지 않을 수 있습니다. 외부 라이브러리 대신 input 태그를

developer-talk.tistory.com

동일한 파일을 업로드하는 경우 input 태그의 onChange 이벤트 핸들러 함수가 정상적으로 동작하지 않는 문제였는데요.

웹 브라우저에서 버튼을 클릭하면 위 사진처럼 파일 탐색기 창이 열립니다. 파일 탐색기 창에서 파일 선택 후 열기 버튼을 클릭하면 선택된 파일을 서버에 바로 업로드해야 하는 작업이 존재했습니다.

 

동일한 파일을 두 번 이상 업로드했을 경우 BackEnd에서 파일명 중복 체크하는 로직을 구현해야 하는데, FrontEnd에서 동일한 파일을 연속해서 선택했을 때, input 태그의 onChange 이벤트 핸들러 함수가 동작하지 않았습니다.

 

다음 예제 소스를 통해 onChange 이벤트 핸들러 함수가 정상적으로 동작했던 시나리오와 동작하지 않았던 시나리오를 살펴봅시다.

 

다음 예제는 파일 탐색기에서 선택한 파일의 이름을 콘솔에 출력하며 codesandbox에서 테스트 가능합니다.

import React, { Component } from "react";
import ReactDOM from "react-dom";

class FileUploadButton extends Component {
  handleFileUpload = (event) => {
    if (event.target.files.length > 0) {
      console.log(event.target.files[0].name);
    }
  };

  render() {
    return (
      <React.Fragment>
        <input
          ref="fileInput"
          onChange={this.handleFileUpload}
          type="file"
          style={{ display: "none" }}
        />
        <button onClick={() => this.refs.fileInput.click()}>Upload File</button>
      </React.Fragment>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<FileUploadButton />, rootElement);

이벤트 핸들러 함수가 정상적으로 동작

  1. 파일 업로드 버튼 클릭
  2. 파일 탐색기 창에서 TestFile_A.jpg 파일 선택 후 열기 버튼 클릭
  3. 파일 탐색기 창에서 TestFile_B.jpg 파일 선택 후 열기 버튼 클릭
  4. 파일 탐색기 창에서 TestFile_A.jpg 파일 선택 후 열기 버튼 클릭


이벤트 핸들러 함수가 동작하지 않음

  1. 파일 업로드 버튼 클릭
  2. 파일 탐색기 창에서 TestFile_A.jpg 파일 선택 후 열기 버튼 클릭
  3. 파일 탐색기 창에서 TestFile_A.jpg 파일 선택 후 열기 버튼 클릭

위 시나리오처럼 동일한 파일을 연속해서 선택한 경우 "TestFile_A.jpg"가 콘솔에 두 번 출력될 거라 예상했지만, 단 한 번만 출력되었습니다.


해결 방법

위 문제가 발생했던 원인은 추측이지만 동일한 파일을 선택하는 경우 JavaScript가 input 태그의 onChange 이벤트 핸들러 함수를 동작하지 않도록 했기 때문이라고 생각됩니다.

 

onChange 이벤트 핸들러 함수가 정상적으로 동작하도록 하기 위해서는 input 태그에 onClick 이벤트 핸들러 함수를 추가하고 event.target.value를 빈 값('') 또는 null로 초기화하는 코드를 작성합니다.

import React, { Component } from "react";
import ReactDOM from "react-dom";

class FileUploadButton extends Component {
  handleFileUpload = (event) => {
    if (event.target.files.length > 0) {
      console.log(event.target.files[0].name);
    }
  };

  handleClick = (event) => {
    event.target.value = null;
  };

  render() {
    return (
      <React.Fragment>
        <input
          ref="fileInput"
          onChange={this.handleFileUpload}
          onClick={this.handleClick}
          type="file"
          style={{ display: "none" }}
          // multiple={false}
        />
        <button onClick={() => this.refs.fileInput.click()}>Upload File</button>
      </React.Fragment>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<FileUploadButton />, rootElement);

event.target.value를 null로 할당하는 이벤트 핸들러 함수를 input 태그의 onClick에 추가하고 동일한 파일을 연속해서 선택하면 onChange 이벤트 핸들러 함수가 정상적으로 동작하는 것을 확인할 수 있습니다.

※ 주의사항
위 해결 방법은 크롬에서는 정상적으로 동직하지만, 다른 브라우저에서는 동작하지 않을 수 있습니다.

참고

 

HTML input file selection event not firing upon selecting the same file

Is there any chance to detect every file selection the user made for an HTML input of type file element? This was asked many times before, but the usually proposed onchange event doesn't fire if ...

stackoverflow.com

 

How to allow input type=file to select the same file in react component

I have a react component which renders a <input type="file"> dom to allow user select images from browser. I found that its onChange method not called when I select the same file. After some

stackoverflow.com

반응형

댓글