이미지 미리보기 기능 구현 방법 비교

JeongHoon Park·2022년 4월 6일
2
post-thumbnail

이미지 미리보기 구현 이유

많은 서비스에 이미지 업로드 기능이 들어간다. 내가 이전 프로젝트들에서 이미지를 업로드했었다. 하지만 업로드할 이미지 미리보기 기능은 필수는 아니였다. 이미지를 제대로 서버에 올리고 나중에 제대로 받아오는 것이 더 중요하다. 하지만 사용자가 내가 올릴 이미지가 어떤 것인지 확인하고 잘못올렸을 경우 다른 이미지로 대체할 수 있도록 한다면 더 나은 사용자 경험을 줄 수 있다. 그래서 많은 서비스들이 이미지 미리보기 기능을 거의 필수로 구현한다.

이번 프로젝트에서는 이미지 미리보기 기능을 필수로 구현하게 되었다. 해당 기능을 구현하기 위해 여러가지 이미지 미리보기 기능을 구현할 수 있는 방법을 찾아보게 되었고 찾아보며 생각한 것들을 정리하게 되었다.


이미지 미리보기 구현 방법 비교

이미지 서버에 올린 후에 보여주기

이미지를 미리보기를 구현하는 여러가지 방법이 있다.
첫번째는 이미지 서버에 올리고 반환된 이미지 주소를 활용하여 보여주는 것이다. 이 경우 몇가지 문제가 있다. 우선 이미지 서버에 이미지를 올리는데 꽤나 시간이 걸린다. 그렇기 때문에 이미지를 선택한 후 이미지를 화면에 띄우기까지 시간 틈이 있어 사용자가 느끼기에 즉각적이지 않다. 만약 여러번 이미지를 교체하게 된다면 대기시간의 불편함은 더 커지게 될 것이다. 두번째는 이미지를 올릴 때마다 서버에 저장되는 이미지가 생기기 때문에 이미지 서버의 비용이 당연히 늘어날 수 밖에 없다. 개인 프로젝트라면 큰 차이가 없겠지만 많은 사람들이 사용하는 서비스라면 엄청난 금액이 지불될 수 있다.


FileReader

구현 방법

이미지 서버와 통신하지 않고 이미지 미리보기를 구현하는 방법으로는 크게 두가지가 있다. 바로 FileReader와 createObjectURL이다. 그중 FileReader를 활용한 구현 방법 먼저 확인해보자.

// JS
const [imgSrc, setImgSrc] = useState('');

const encodeFileToBase64 = (fileBlob) => {
  const reader = new FileReader();
  reader.readAsDataURL(fileBlob);
  return new Promise((resolve) => {
    reader.onload = () => {
      setImgSrc(reader.result);
      resolve();
    };
  });
};

// HTML(input)
<input
  type="file"
  onChange={(e) => {
    encodeFileToBase64(e.target.files[0]);
  }}
/>

위의 encodeFileToBase64함수는 다음과 같이 진행된다.

  • FileReader의 인스턴스(reader)를 생성한다.
  • 인자로 받아온 fileBlob을 base64 포맷으로 인코딩한다.
  • 인코딩이 마무리되면 reader.result 안의 문자열을 imgSrc에 저장한다.
  • resolve를 호출하여 Promise가 이행상태가 된다.

FileReader의 특성

  • FileReader의 경우 IE10을 포함한 모든 모던 브라우저를 지원한다.
  • 많은 메모리를 사용하고 해당 메모리를 우리가 지울 수 없다. 가비지 컬렉터에 의해 자동으로 지워지게 된다.
  • 이미지를 띄우는데 즉각적이지 않고 약간의 시간이 걸린다.

createObjectURL

구현 방법

마지막으로 내가 선택한 createObjectURL이다.

// JS
const [imgSrc, setImgSrc] = useState('');

const saveFileImage = (fileBlob) => {
  const fileUrl = URL.createObjectURL(fileBlob);
  setImgSrc(fileUrl);
};

// HTML(input)
<input
  type="file"
  onChange={(e) => {
    saveFileImage(e.target.files[0]);
  }}
/>

코드를 보면 훨씬 간결해졌다. saveFileImage함수는 다음과 같이 진행된다.

  • URL.createObjectURL을 사용하여 인자로 받아온 fileBlob을 가리키는 URL을 DOMString으로 만들어준다.
  • 만들어진 URL을 imgSrc에 저장한다.

revokeObjectURL을 활용한 객체 URL 해제

createObjectURL을 활용한 방식은 같은 객체를 사용하더라도, createObjectURL()을 매번 호출할 때마다 새로운 객체 URL을 생성한다. 그렇기 때문에 생성된 객체 URL을 직접 하나씩 해제해주어야한다.

URL.revokeObjectURL(objURL);

objURL을 해제해주는 방법은 간단한다. 위처럼 해제하려는 objURL URL.revokeObjectURL() 함수 안에 넣어서 호출하면 된다.

createObjURL 특성

  • createObjectURL은 IE10을 포함한 모든 모던 브라우저를 지원한다.
  • 해시가 포함된 URL을 반환한다.
  • document의 언로드 이벤트가 일어나거나 직접 revokeObjectURL을 실행하지 않으면 메모리가 남아있게된다.
  • 이미지를 즉각적으로 띄울 수 있다.

마무리

위에서 이미지 미리보기를 구현 할 수 있는 여러가지 방법을 소개했다. 여러가지 방법을 소개했지만 앞선 두가지 방법은 장점보다 단점이 많았기 때문에 createObjectURL 방식을 추천한다.

profile
Develop myself, FE developer!

0개의 댓글