이미지 업로드 후 미리보기 기능 구현(createObjectURL)

CHAENG·2024년 7월 25일
0

FrontEnd

목록 보기
7/10

서버와 url을 주고받는 기능을 구현하기 이전에

사용자 입력으로 이미지를 업로드하고, 업로드한 이미지를 클라이언트측에서 미리보기로 확인할 수 있는 기능을 구현하고자 했다.

FileReader와 createOjbectURL 중 createObject URL방식이 변환된 string의 길이가 더 짧고, 인코딩 디코딩 과정을 거치지 않아도 된다는 점에서 해당 방식을 활용하기로 결정했다.

참조 링크

  • ForrmData

https://velog.io/@yeogenius/React-클라우드-스토리지에-이미지-파일-업로드-하기

https://velog.io/@xxyeon129/Formdata로-이미지-업로드하기

  • createObjectURL

https://hojung-testbench.tistory.com/entry/React-파일-업로드-기능-구현

https://mieumje.tistory.com/164


✅ Blob

웹에서 멀티미디어 데이터를 다룰 때 Blob이라는 데이터 타입을 주로 사용한다.

파일이나 영상 이미지와 같이 용량은 큰 파일은 key,valuye 쌍으로 이루어진 json 형식으로 다루기 어렵기 때문이다.

Blob (Binary Large Object)에는 데이터 사이즈를 알아내거나, 데이터 송수신을 위해서 더 작은 blob객체로 나누는 등, 다양한 범위에서 사용될 수 있다.

Blob은 데이터 자체라기보다, 데이터를 처리하거나 간접적으로 접근하기 위한 객체라고 볼 수 있다.

Blob을 상속받은 File 객체로컬 파일을 다룰 수 있으며, 추가로 파일명과 최종 수정일을 확인할 수 있는 프로퍼티가 추가되어있다.

✅ URL.createObjectURL

해당 메소드를 통해 사용자가 업로드한 파일 미리보기 기능을 구현할 수 있다.

  • URL 객체의 createObjectURL()메서드는 File, Blob 객체를 가르키는 URL을 생성한다.
    • 업로드한 파일의 고유한 URL을 생성하게 된다.
  • 생성된 URL을 통해서 미리보기 기능을 구현할 수 있으며, 이때 만들어진 url은 서버로 전송되는 것이 아닌, client 단에서만 사용 가능하다.
    • 서버로 전송하기 위해서는 FormData를 활용해야한다.
  • 고유한 URL객체는 Document가 닫히기 전까지 유지되며, revokeObjectURL()을 통해서 그 전에 해제할 수 있다.
    • 한 화면에서 계속 이미지를 바꾸면 매번 고유한 URL이 생성되기 때문에, 이미지가 변경될 때 마다 revokeObjectURL()을 해주는 것이 메모리측면에서 좋다.

구현

이미지를 사용자로부터 받기 위해서는 input 태그를 활용해야 한다.

하지만 버튼기능을 통해서 사용자로부터 이미지를 받기 위해서 input 태그는 hidden 속성을 적용하고, useRef를 활용하여 input태그에 직접적으로 접근하여 값을 가져오도록 했다.

  • useRef (input, button)
const fileInputRef = useRef(null); // file input ref

// input을 가르키는 ref
  const handleFileInput = useCallback(() => {
    if (!fileInputRef.current) {
      return;
    }
    fileInputRef.current.click();
  }, []);
  
  
  <button onClick={handleFileInput}>
    Upload
  </button>
  <input
    className="hidden"
    type="file"
    accept="image/jpg, image/jpeg, image/png"
    ref={fileInputRef}
    onChange={onImageChange}
  />
  • 이미지 업로드 (onImageChange)

input 태그를 통해 업로드된 파일이 바뀔 때 마다 해당 메소드가 실행된다.

해당 메소드를 통해서 입력된 파일의 정보를 저장하고, URL을 생성하여 미리보기 기능을 구현할 수 있다.

  const [imageFile, setImageFile] = useState(null); // upload한 파일 정보 저장

	// 입력한 이미지 데이터 처리
  const onImageChange = useCallback((e) => {
    const fileList = e.target.files; // 입력된 파일 형태의 데이터

    // 하나의 파일 데이터만 처리
    if (fileList && fileList[0]) {
      setImageFile(fileList[0]); // 업로드 된 파일의 정보 저장
    }
  }, []);

하나의 파일만 다루기때문에 fileList 배열에 [0] 번째 해당하는 인덱스의 값만 활용한다.

  • 업로드 된 이미지 파일 미리보기

파일이 업로드 되면 createObjectURL 메소드를 통해서 fileList[0] 객체의 URL을 생성한다.

  const [imagePreview, setImagePreview] = useState(""); // upload한 파일 미리보기

	// 입력한 이미지 데이터 처리
  const onImageChange = useCallback((e) => {
    const fileList = e.target.files; // 입력된 파일 형태의 데이터

    // 하나의 파일 데이터만 처리
    if (fileList && fileList[0]) {
      setImageFile(fileList[0]); // 업로드 된 파일의 정보 저장

      // 이미지 미리보기 기능을 위해서 브라우저상에서 url을 생성함
      const imagePreviewUrl = URL.createObjectURL(fileList[0]);
      setImagePreview(imagePreviewUrl);
    }
  }, []);
  • Blob URL 해제

createObjectURL로 생성된 Blob URL은 revoekObjectURL을 호출하기 전까지 브라우저 메모리에 존재한다.

따라서 메모리 누수를 방지하기 위해서, imagePreview의 값이 변경될 때 마다 revokeObjectURL을 호출하여 Blob URL을 해제한다.

 // 이미지 업로드 후 Blob URL 해제(메모리 누수 방지용)
  useEffect(() => {
    if (imagePreview) {
      return () => URL.revokeObjectURL(imagePreview);
    }
  }, [imagePreview]);
profile
FrontEnd Developer.

0개의 댓글

관련 채용 정보