개발 마라톤

10/12 - 이미지 프리뷰 본문

--- Project ---/CharFlyer : 캐플라이어

10/12 - 이미지 프리뷰

망__고 2023. 10. 12. 17:10

FileReader API로 이미지 프리뷰 하기

리액트에서 이미지 미리보기 만들어보기 (React Image Preview) — 찐이의 개발 연결구과 (tistory.com)

 

리액트에서 이미지 미리보기 만들어보기 (React Image Preview)

서론 HTML의 input 태그로 이미지를 핸들링할 때 현재 선택한 이미지를 미리 보고 싶은 경우가 있다. 라이브러리를 통해 구현할 수도 있지만 어떤 방식으로 구현할 수 있을까 고민해보았다. Web API

nukw0n-dev.tistory.com

FileReader API는 File, Blob 객체를 base64로 인코딩하여 사용할 수 있도록 한다.

내용 사용 예
FileReader 사용 const fileReader = new FileReader();
FileReader로 파일 인코딩 fileReader.readAsDataURL(File)
FileReader의 인코딩 결과 받아오기 fileReader.reusult;
FileReader가 파일을 읽어 왔을 때 수행하는 이벤트 지정 fileReader.onload = function () {}

위에서 명시한 메소드들을 통해 코드를 작성해보았다.

const useEncodeFileToBase64 = (file : File, setState : React.Dispatch<React.SetStateAction<string | null>>) => {
  // 넘겨받은 file이 File 타입인지 확인 후 아니라면 return 합니다. (관련 오류 있었음)
  if(!(file instanceof File)) return;
  
  const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => {
      setState(reader.result as string);
    }
  };


export default useEncodeFileToBase64;

인자로 받은 파일 한 개를 넘겨받은 setState를 통해 state에 인코딩 값을 할당해주는 커스텀 훅을 작성하였다.

  // 프로필 업로드
  const profileInputRef = useRef<HTMLInputElement | null>(null);
  const profileImageRef = useRef<HTMLImageElement | null>(null);
  const inputProfileImage = (e: React.ChangeEvent<HTMLInputElement>) => {
    // 이미지 프리뷰
    if(!e.target.files) return;
    const file = e.target.files[0];

    // 파일 용량 검사
    if(file.size > LIMITS_FILE_SIZE) {
      alert(`이미지는 ${LIMITS_FILE_SIZE / 1024 ** 2}MB 이하여야 합니다.`);
      return;
    }
    // File 객체를 base64로 인코딩해주는 훅 사용
    useEncodeFileToBase64(file, setProfileImage);
  }
  
  useEffect(()=> {
    if(profileImageRef.current)
      profileImageRef.current.src = profileImage || '';
  }, [profileImage])

 훅을 사용하는 컴포넌트에서는 파일이 존재하는지 검사하고, 파일 용량을 검사 후 할당하도록 코드를 작성하였다.

결과

 

+ 추가

코드 정리를 하다 인코딩된 base64 값을 반환하는 일반적인 유틸 함수로 변환했는데 코드는 다음과 같다.

const encodeFileToBase64 = (file : File): Promise<string | null> | void => {
  // 넘겨받은 file이 File 타입인지 확인 후 아니라면 return 합니다. (관련 오류 있었음)
  if(!(file instanceof File)) return;
  
  return new Promise<string>(async (resolve, reject) => {
    const reader = new FileReader();

    reader.onload = (event) => {
      const base64Data = event.target?.result;
      resolve(base64Data as string);
    };

    reader.onerror = (error) => {
      reject(error);
    };

    reader.readAsDataURL(file);
  });
};


export default encodeFileToBase64;

호출하는 부분에서는 null에 관한 타입 처리를 해주면 되겠다.

Comments