Frontend/Today I Learned

[React, TS] Input 이미지 파일 미리보기

joycie416 2024. 10. 14. 23:12

프로필 이미지를 수정할 때, 업로드한 이미지가 어떻게 보일지 궁금하다. 따라서 파일을 업로드하면 미리보기를 띄우기로 했다. 

 

그러려면 JS의 `FileReader`가 필요하며, 사용할 메소드는 `readAsDataURL`, `onloadend` `result` 이다.

 

`readAsDataURL`은 업로드한 파일은 컨텐츠를 읽어오는 역할을 한다. `onloadend`에는 파일을 읽는 행위가 종료되면 실행할 함수를 입력하면 된다. `onloadend`에 작성 한 함수 내부에 파일 경로 저장하는 내용이 필요한데, 이때 `result`를 통해 `readAsDataURL`의 결과로 URL로 데이터를 불러올 수 있으며, 해당 URL을 imgPath에 저장해 미리보기를 띄워주었다. 이 imgPath를 img 태그의 src에 할당해주면 된다.

 

또한 img 태그에 `accept` 속성을 통해 받을 파일의 유형을 선택할 수 있다. 이미지 파일만 필요하므로 `accept="image/*"`로 설정해 모든 종류의 이미지 파일을 받을 수 있게 했다. 만약 `.jpg`와 같은 특정 확장자만 원한다면 `"image/jpg"`와 같이 입력하면 된다.

 

 

"use client";

import ...

const STORAGE = "profiles";
const EditProfileModal = ({
  user,
  setShowModal
}: {
  user: User | null;
  setShowModal: Dispatch<SetStateAction<boolean>>;
}) => {
  const [profileImg, setProfileImg] = useState<File | null>(null);
  const [imgPath, setImgPath] = useState<string>("");

  const {
    data: { publicUrl: userImg }
  } = supabase.storage.from(STORAGE).getPublicUrl(user?.user_metadata?.profile_img ?? "default");
  const {
    data: { publicUrl: defaultImg }
  } = supabase.storage.from(STORAGE).getPublicUrl("default");

  // 불러온 이미지 미리 보기
  const previewImg = (e: ChangeEvent<HTMLInputElement>) => {
    const file = (e.target?.files as FileList)[0];
    console.log("file :", file);
    if (!file) {
      setImgPath(userImg);
    } else {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onloadend = () => {
        setImgPath(reader.result as string);
      };
    }
  };
  return (
    <div className="w-full h-full flex flex-col justify-between items-center">
      <img
        src={!imgPath ? userImg : imgPath}
        className="h-[200px] aspect-square object-cover border-2 border-gray-300 rounded-full mx-auto"
      />
      <Input
        type="file"
        className="cursor-pointer"
        accept="image/*" // image 파일만 받을 수 있도록
        onChange={(e) => {
          setProfileImg(!e.target.files ? null : e.target.files[0]);
          previewImg(e);
        }}
        alt="프로필 이미지"
      />
    </div>
  );
};

export default EditProfileModal;