본문 바로가기
FrontEnd ✨/❄️ React

[React] 이미지 업로드 & 미리보기 기능 만들기 (1)

by 뽀짜꼬 2023. 8. 24.
728x90
반응형

리뷰 작성을 하는 창에서 사진 3개를 첨부할 수 있도록 하고, 사진 미리보기를 띄워주도록 해야했다.

 

이렇게 세 개의 사진을 각각 추가할 수 있어야 한다.

이번 포스팅은 단순 기능 구현과 공부한것들의 기록이고, 다음 포스팅에서 서버와의 연결을 기록하도록 하겠다.


✨알아야할것

FileReader

  • Web API
    • 웹 브라우저에서 제공하는 API
    • 개발자가 브라우저 상에 쉽게 개발할 수 있도록 도와주는 객체의 모음
  • 파일을 읽을 수 있게 해주는 객체
  • File, Blob 객체를 핸들링할 때 사용됨.
    • Blob : 이미지, 사운드, 비디오와 같은 멀티미디어 데이터 다룰때 사용
      • 데이터의 크기(Byte) 및 데이터 송수신을 위한 작은 Blob 객체로 나누는 등의 작업에 사용함.
  • 위의 객체를 사용해 특정 파일을 읽어들여 JS에서 파일에 접근할 수 있도록 도와줌

readAsDataURL

  • 파일을 URL로 만들 수 있음, 파일 정보를 주소처럼 사용할 수 있다.
  • 바이너리 파일을 읽어들일 때 사용됨.
  • base64로 이루어진 데이터를 반환받을 수 있음.

+)Base64

바이너리 데이터를 문자 코드에 영향 받지 않는 공통 ASCII 문자로 표현하기 위해 만들어진 인코딩

Promise

  • JS에서 비동기 처리에 활용되는 객체. (순차적X, 다음 코드 먼저 실행)
  • 서버에 데이터를 요청했을 때, 데이터가 모두 받아오기 전에 웹에 출력하려고 할 때 발생하는 오류를 방지하기 위해 활용
  • 콜백 함수 인자인 resolve를 실행하면 이행된(Fulfilled) 상태 (완료된 상태)
  • reject는 호출 시 실패(Rejected) 상태

버튼 꾸미기

  • <input>버튼이 생겨서 display:none으로 숨기고, <label>태그를 사용할 수 있음

What is <label> 태그?

  • 폼의 양식에 이름을 붙이는 태그
  • 주요 속성은 for
    • label의 for 값과 양식의 id 값이 같으면 연결된다.
  • label을 클릭하면, 연결된 양식에 입력할 수 있도록 하거나, 체크를 하거나, 체크를 해제함

✨작성한 코드

<label htmlFor="UploadImg1" className={styles.UploadImgButton}>
    {imageUploaded ? null : <img src="/img/plusicon.png" className={styles.plusImage} />}
</label>
<input
    type="file"
    accept="image/*"
    id="UploadImg1"
    onChange={FileUploadHandler}
/>
{imageSrc && <img src={imageSrc} alt="preview-img" className={styles.uploadedImage} />}

< input type="file" accept="image/*" />

를 설정하면 컴퓨터의 파일 중, 이미지의 형식만 업로드 할 수 있다.

 

<label htmlFor="UploadImg1">, <input id="UploadImg1">

위에서 말했듯이, label의 for값과 양식의 id의 값이 같으면 연결을 할 수 있다.

리액트에서는 label의 for를 htmlFor로 작성을 해주어야 한다. 둘의 아이디를 똑같이 맞추어주면 연결이 된다.

위에서 설정한 + 그림을 누르면 파일 선택 창이 열린다.

 

{imageUploaded ? null : <img src="/img/plusicon.png"/>}

이 코드는 이미지가 업로드 되었는지의 여부를 통해 + 이미지를 보여주고 숨기는 코드이다.

이미지가 첨부되었을때 아이콘은 숨겨지고, 미리보기 이미지만 띄워주게 하기 위해서이다.

삼항연산자를 통해 imageUploaded가 참 (이미지가 업로드 되었다)면 null을 반환함으로써 +를 보여주지 않는다.

 

    const encodeFileToBase64 = (fileBlob) => {
        //객체 생성
        const reader = new FileReader();
        reader.readAsDataURL(fileBlob);
        return new Promise((resolve) => {
            reader.onload = () => {
                setImageSrc(reader.result);
                resolve();
            };
        });
    };

파일을 읽을 수 있는 FileReader객체를 생성한다. readAsDataURL을 통해 파일을 URL로 만들어준다.

그리고 이를 ImageSrc에 저장한다.

 

{imageSrc && <img src={imageSrc} alt="preview-img" />}

이렇게 되면 위의 코드가 설명이 되겠다.

imageSrc가 존재할 경우 미리보기 이미지를 띄워주는 코드이다.

 

    const FileUploadHandler = (e) => {
        const file = e.target.files[0];
        if (file) {
            encodeFileToBase64(file).then(() => {
                setImageUploaded(true); // + 아이콘 숨기고 보여주기 위한 부분
                setImageFile1(file); // 이미지 파일 설정 (저장) 서버 전송을 위한 부분
            });
        } else {
            setImageSrc('');
            setImageUploaded(false); // + 아이콘
            setImageFile1(null);
        }
    };

const file = e.target.files[0];

e.target.files 배열에서 input에서 선택한 파일의 정보를 얻어온다.


💡개발 도중 발생한 문제 상황들

문제 01 - 파일 업로드 상황에서 ‘취소’를 눌렀을 경우 오류 발생

const FileUploadHandler = (e) => {
        const file = e.target.files[0];
        if (file){
            encodeFileToBase64(file);
        } else {
            setImageSrc('');
        }
    }

이렇게 if문으로 해결했다. 

문제 02 - 이미지 파일 업로드 3개를 해야함. (각자 따로)

각 이미지 상태를 담는 state를 3개 만들었다.

나중에 최적화 해보도록 하겠다.

 


참고 자료

 

[React] 이미지 업로드하고 미리보기

📸 input태그와 label태그, 그리고 FileReader API사용해보기!

velog.io

 

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

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

nukw0n-dev.tistory.com

 

JS - 파일API : FileReader() 객체

FileReader() 객체는 비동기적으로 파일의 내용을 읽어들이는 데 사용됩니다. 형식은 다음과 같습니다. var reader = new FileReader(); 속 성 설 명 ...

www.habonyphp.com

 

 

728x90
반응형