[React|Refactor|TRACK1] 이미지 미리보기 Cutom Hooks
TRACK1 리팩토링 이야기, 이미지 미리보기 커스텀 훅
커스텀 훅
리액트 공식문서 를 통해 어떻게 커스텀 훅을 잘 사용할지 고민하며 만들어 보았다.
컴포넌트 분리를 고민할 때, 한 컴포넌트에는 한 가지의 기능만을 가지도록 만든다는 것이 큰 원칙이었다.
커스텀 훅은 또 다른 함수(기능)을 따로 분리함으로써 컴포넌트를 어지럽히지 않고 기능들을 쌓아올라갈 수 있지 않을까 생각했다.
특히, 이미지 미리보기 부분은 내가 지금 개발하고 있는 프로듀서 프로필 수정 페이지 뿐만 아니라 회원가입, 보컬 프로필 수정, 트랙 게시글 올리기 등등 아주 많이 사용하기 때문에 재사용성에 있어서 꼭 꼭 필요했다.
이미지 업로드 UI
export default function ProducerImageEdit() {
function getImageFile(e: React.ChangeEvent<HTMLInputElement>) {
e.preventDefault();
const file = e.target.files;
console.log(file);
}
return (
<>
{/* 프로듀서 프로필 이미지 업로더 */}
<ProfileImageContainer>
<ProfileImage />
<ChangePhotoIcon />
<FileInput type="file" onChange={getImageFile} />
</ProfileImageContainer>
</>
);
}
우선 input 태그로 file을 입력 받는다. 그럼 profileImage가 img 태그인데 여기 src로 이미지를 미리보기로 띄울 것이다!
그 다음, onChange로 key 이벤트를 input을 통해 받을 때, file이 계속 바뀌어서 들어가도록 했고 확인을 위해 log를 찍어보았다.
미리보기 커스텀 훅 작성
import { useState } from "react";
export default function useShowImage(imageFile: File | Blob | undefined | null) {
const [showImage, setShowImage] = useState<string>();
if (imageFile) {
const reader = new FileReader();
reader.readAsDataURL(imageFile);
reader.onload = (e) => {
setShowImage(e.target?.result as string);
};
}
return showImage;
}
먼저, 사용하는 곳에서 이미지 파일을 받아올 것이다.
공식문서에서 팁: Hook에서 Hook으로 정보 전달하기 부분을 읽고 만들었다.
컴포넌트에서 input 된 파일을 useState로 담아 커스텀 훅을 불러올 때 보내줄 것이다.
어쨋든 그렇게 받은 파일을 FileReader라는 자바스크립트 web API를 이용하여 이미지 url을 뽑아낼 것이다.
- 객체 생성
- readAsDataURL, readAsText, readAsArrayBuffer 등의 메서드를 통해 파일을 읽는다.
- onload 함수 이용 -> load 이벤트 핸들러에서 e.target.result를 사용하여 파일의 내용을 얻을 수 있다.
- 얻어낸 이미지 url을 담아서 return한다.
훅을 통해 알아낸 이미지 url을 불러와서 사용하기
export default function ProducerImageEdit() {
const [image, setImage] = useState<File | Blob | undefined | null>(undefined);
const showImage = useImagePreview(image);
function getImageFile(e: React.ChangeEvent<HTMLInputElement>) {
e.preventDefault();
const file = e.target.files?.[0];
setImage(file);
}
return (
<>
{/* 프로듀서 프로필 이미지 업로더 */}
<ProfileImageContainer>
{/* 사용자가 넣은 이미지 or 기본 사람 이미지 */}
{/* {isImageUploaded ? <ProfileImage src={String(showImage)} /> : <ProfileImage src={String(profileImage)} />} */}
<ProfileImage src={String(showImage)} />
<ChangePhotoIcon />
<FileInput type="file" onChange={getImageFile} />
</ProfileImageContainer>
</>
);
}