이미지 업로드 전 미리보기

Written on July 10, 2019

이미지를 업로드하기 전에 어떤 이미지를 선택했는지 미리 보여주고, 대표이미지를 설정하거나, 필요없는 파일은 삭제하도록 하는 기능이 필요하다. 이번 포스트에서는 미리보기 기능을 구현하는 방법을 알아보겠다.

이미지 디스플레이는 <img> 태그로 하는데, 이를 위해서는 이미지에 대한 파일 경로(url)이 필요하며, 이는 FileReader 객체를 활용해서 구현할 수 있다.

파일선택 input 만들기

리액트로 이미지 업로더 구현하기에서 사용한 <inupt type="file">을 이용하여, 기본 파일선택 틀을 만든다.

class App extends React.Component {
  state = { selectedFiles: null };
  fileChangedHandler = event => {
    const files = event.target.files;
    this.setState({
      selectedFiles: files
    });
  };
  render() {
    return (
      <div className="App" style={{ marginTop: "100px" }}>
        <input type="file" multiple onChange={this.fileChangedHandler} />
      </div>
    );
  }
}

componentDidUpdate를 이용하여 renderPreview() 트리거 만들기

선택된 파일이 바뀔 때 마다(state가 변경될 때마다) 프리뷰를 다시 그릴 수 있도록 하기 위해서 React Life Cycle의 componentDidUpdate 메서드를 사용한다.

componentDidUpdate = prevState => {
  if (prevState.selectedFiles !== this.state.selectedFiles) {
    this.renderPreviews();
  }
};

renderPreview() 함수 작성

먼저, preview 이미지의 parent node를 만들어 주는데 여기에 ‘preview-container’라는 id를 부여하여 돔에 접근할 수 있도록 한다.

  render() {
    return (
      <div className="App" style={{ marginTop: "100px" }}>
        <input type="file" multiple onChange={this.fileChangedHandler} />
        <div id="preview-container" />
      </div>
    );
  }

document.createElement("img")로 이미지 태그를 만들고, “preview-container” div에 자식노드로 추가해준다. img 태그에 src 속성을 주어야 하는데, 이는 FileReaderreadAsDataURL 메서드를 이용한다. readAsDataURL 메서드의 실행결과는 FileReaderresult 프로퍼티에서 확인할 수 있는데, 이는 메서드가 완전히 실행되고 나서야 확인할 수 있으므로, FileReaderonload 이벤트핸들러를 부여하여 메서드가 실행되고 나면, img 태그의 srcFileReaderresult를 부여하라. 라고 정의하면 된다. 코드로 나타내면,

  renderPreviews = () => {
    const { selectedFiles } = this.state;
    const previewContainer = document.getElementById("preview-container");
    for (let i = 0; i < selectedFiles.length; i++) {
      const preview = document.createElement("img");
      preview.id = `preview_${i}`;
      previewContainer.appendChild(preview);
      const reader = new FileReader();
      reader.onload = function(evt) {
        preview.src = reader.result;
      };
      reader.readAsDataURL(selectedFiles[i]);
    }
  };


최종 코드는 아래와 같다.

class App extends React.Component {
  state = { selectedFiles: null };
  componentDidUpdate = prevState => {
    if (prevState.selectedFiles !== this.state.selectedFiles) {
      this.renderPreviews();
    }
  };

  renderPreviews = () => {
    const { selectedFiles } = this.state;
    const previewContainer = document.getElementById("preview-container");
    for (let i = 0; i < selectedFiles.length; i++) {
      const preview = document.createElement("img");
      preview.id = `preview_${i}`;
      previewContainer.appendChild(preview);
      const reader = new FileReader();
      reader.onload = function(evt) {
        preview.src = reader.result;
      };
      reader.readAsDataURL(selectedFiles[i]);
    }
  };
  fileChangedHandler = event => {
    const files = event.target.files;
    this.setState({
      selectedFiles: files
    });
  };
  render() {
    return (
      <div className="App" style={{ marginTop: "100px" }}>
        <input type="file" multiple onChange={this.fileChangedHandler} />
        <div id="preview-container" />
      </div>
    );
  }
}

export default App;

관련 post

리액트로 이미지 업로더 구현하기

👩🏻‍💻 배우는 것을 즐기는 프론트엔드 개발자 입니다
부족한 블로그에 방문해 주셔서 감사합니다 🙇🏻‍♀️

in the process of becoming the best version of myself