[React] 이미지 눌러서 파일 업로드 & 이미지 미리보기 기능

김다빈·2023년 10월 26일
1

개인 프로젝트

목록 보기
6/7
post-thumbnail
post-custom-banner

일전에 패캠 JS과제로 이미지 업로드 및 미리보기 기능을 경험해봤지만
당시에는 JS 지식이 부족했고 (물론 지금도 많이 부족함...)
그냥 구글링으로 얻어낸 코드를 복붙하고 제대로 이해하지 못한 것 같아서
이번 기회를 통해 코드 한줄 한줄에 대한 이해를 기반으로 파편화된 지식을 정리해보려 한다.

이미지 업로드 기능

//EditPhoto.tsx

const EditPhoto = () => {
  const [imgFile, setImgFile] = useState<File>();
  const [imgPath, setImgPath] = useState("");
  const imgRef = useRef<HTMLInputElement>(null);
  const MAX_IMAGE_SIZE_BYTES = 1024 * 1024 * 2;


  return (
    <label htmlFor="photo">
      <img
        //사용자가 이미지 파일을 업로드하면 해당 이미지를 보여주고, 없으면 기본 이미지를 보여준다.
        src={imgPath ? imgPath : `/images/upload.png`}
        alt="이미지 업로드"
      />
    </label>
    <input
      type="file"
      id="photo"
      name="photo"
      accept=".png, .jpeg, .jpg"
      onChange={previewImage}
      ref={imgRef}
    />
  );
};

export default EditPhoto;

이미지 업로드 기능은 매우 간단하다.
<input type="file> 태그를 활용하여 만들 수 있다.

파일 형식 지정

MDN - HTML attribute: accept

좀 더 구체적으로는 이미지만 받고 싶을 경우 accept 속성을 사용해서 파일 형식을 특정해줄 수 있다.

accept=".png, .jpeg, .jpg"
accept="image/jpg, image/png, video/mp4, video/avi"

두 가지 방식 모두 가능하다.

만약 이미지 파일만 받을 수 있는 경우라면 전자처럼 작성하는 방식이 편할 것이고,
동영상 파일 등 여러 가지 형식을 복합적으로 받을 수 있는 경우라면 후자처럼 작성하는 방식이 좋을 것 같다.

이미지 사이즈 제한

사진의 사이즈가 너무 크면 DB 관리도 힘들고, 업로드하고 불러오는 데에도 좋지 않기 때문에 제한을 두어 받는 것이 좋다.

if (img.size > MAX_IMAGE_SIZE_BYTES) {
  alert("최대 2MB까지 업로드 가능합니다.");
  return;
}

이미지 눌러서 파일 업로드 (input file 업로드 버튼 커스텀)

<input type="file> 태그로 작성하게되면 기본으로 제공하는 파일 선택 버튼이 생성된다.
이때, 더 예쁜 UI를 위해 이 버튼을 눌러서 파일을 업로드하지 않고, 위의 이미지를 눌러 파일을 업로드하게 할 수 있다.

<label HtmlFor=""> 속성 사용

기본 html에서는 <label for=""> 이지만, 리액트에서는 <label HtmlFor=""> 라고 사용해야 한다. 그냥 for 이라고 작성하면 리액트에서는 반복문 for 로 인식한다고 한다.

<label> 태그의 htmlFor 속성을 사용하여 input 태그와 연결시킨다.

<label> 태그 내부에 보여줄 이미지 또는 텍스트 등을 입력하고,
<input type="file>의 스타일링을 display:none 으로 설정하면 이미지를 눌러서 파일을 업로드할 수 있게 된다.


이미지 미리보기 기능

FileReader Web API

MDN - FileReader

new FileReader()

FileReader API를 사용하기 위해 생성자로 선언해 준다.

reader.readAsDataURL(img)

바이너리 파일을 Base64 Encode 문자열로 반환한다.

Ex.) data:image/jpeg; base64, GDYG…
이렇게 취득한 문자열로 이미지를 브라우저로 바로 출력시키면 사용자는 해당 이미지를 동적으로 확인할 수 있다.

reader.onload

파일 읽기를 성공적으로 완료했을 때 실행할 동작을 작성해준다.

reader.onload = () => {
  setImgPath(reader.result as string);
};

previewImage 함수

사용자가 업로드한 이미지가 있을 경우 해당 이미지를 미리 보여주는 기능을 하는 함수이다.

const previewImage = () => {
  if (imgRef.current && imgRef.current.files) {
    const img = imgRef.current.files[0];
    setImgFile(img);
    
    //이미지 미리보기 기능
    const reader = new FileReader();
    reader.readAsDataURL(img);
    reader.onload = () => {
      setImgPath(reader.result as string);
    };
  }
};

참고 문서

Your House Today/ #2 글쓰기( Posting)/ 카테고리 드롭다운/ 이미지업로드

profile
Hello, World
post-custom-banner

0개의 댓글