이미지 업로드 전 미리보기
이미지를 업로드하기 전에 어떤 이미지를 선택했는지 미리 보여주고, 대표이미지를 설정하거나, 필요없는 파일은 삭제하도록 하는 기능이 필요하다. 이번 포스트에서는 미리보기 기능을 구현하는 방법을 알아보겠다.
이미지 디스플레이는 <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
속성을 주어야 하는데, 이는 FileReader
의 readAsDataURL
메서드를 이용한다. readAsDataURL
메서드의 실행결과는 FileReader
의 result
프로퍼티에서 확인할 수 있는데, 이는 메서드가 완전히 실행되고 나서야 확인할 수 있으므로, FileReader
에 onload
이벤트핸들러를 부여하여 메서드가 실행되고 나면, img
태그의 src
에 FileReader
의 result
를 부여하라. 라고 정의하면 된다. 코드로 나타내면,
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